GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/utils/cpu.cpp Lines: 42 43 97.7 %
Date: 2021-03-17 Branches: 26 52 50.0 %

Line Branch Exec Source
1
/*
2
 *  The ManaPlus Client
3
 *  Copyright (C) 2013-2019  The ManaPlus Developers
4
 *  Copyright (C) 2019-2021  Andrei Karas
5
 *
6
 *  This file is part of The ManaPlus Client.
7
 *
8
 *  This program is free software; you can redistribute it and/or modify
9
 *  it under the terms of the GNU General Public License as published by
10
 *  the Free Software Foundation; either version 2 of the License, or
11
 *  any later version.
12
 *
13
 *  This program is distributed in the hope that it will be useful,
14
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 *  GNU General Public License for more details.
17
 *
18
 *  You should have received a copy of the GNU General Public License
19
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
20
 */
21
22
#include "utils/cpu.h"
23
24
#include "logger.h"
25
26
#if (defined(__amd64__) || defined(__i386__)) && defined(__GNUC__) \
27
    && (GCC_VERSION >= 40800) && !defined(ANDROID)
28
// nothing
29
#elif defined(__linux__) || defined(__linux)
30
#include "utils/foreach.h"
31
#include "utils/stringutils.h"
32
#endif  // (defined(__amd64__) || defined(__i386__)) && defined(__GNUC__)
33
        // && (GCC_VERSION >= 40800) && !defined(ANDROID)
34
35
#ifdef USE_SDL2
36
#include <SDL_cpuinfo.h>
37
#endif  // USE_SDL2
38
39
#include "debug.h"
40
41
namespace
42
{
43
    uint32_t mCpuFlags;
44
}  // namespace
45
46
1
void Cpu::detect()
47
{
48
#if (defined(__amd64__) || defined(__i386__)) && defined(__GNUC__) \
49
    && (GCC_VERSION >= 40800) && !defined(ANDROID)
50
1
    __builtin_cpu_init();
51
1
    if (__builtin_cpu_supports ("mmx"))
52
1
        mCpuFlags |= FEATURE_MMX;
53
1
    if (__builtin_cpu_supports ("sse"))
54
1
        mCpuFlags |= FEATURE_SSE;
55
1
    if (__builtin_cpu_supports ("sse2"))
56
1
        mCpuFlags |= FEATURE_SSE2;
57
1
    if (__builtin_cpu_supports ("ssse3"))
58
1
        mCpuFlags |= FEATURE_SSSE3;
59
1
    if (__builtin_cpu_supports ("sse4.1"))
60
1
        mCpuFlags |= FEATURE_SSE4;
61
1
    if (__builtin_cpu_supports ("sse4.2"))
62
1
        mCpuFlags |= FEATURE_SSE42;
63
1
    if (__builtin_cpu_supports ("avx"))
64
1
        mCpuFlags |= FEATURE_AVX;
65
1
    if (__builtin_cpu_supports ("avx2"))
66
1
        mCpuFlags |= FEATURE_AVX2;
67
1
    printFlags();
68
#elif defined(__linux__) || defined(__linux)
69
    FILE *file = fopen("/proc/cpuinfo", "r");
70
    char buf[1001];
71
    if (file == nullptr)
72
        return;
73
    while (fgets(buf, 1000, file) != nullptr)
74
    {
75
        std::string str = buf;
76
        if (findFirst(str, "flags"))
77
        {
78
            size_t idx = str.find(':');
79
            if (idx == std::string::npos)
80
                continue;
81
            str = str.substr(idx + 1);
82
            trim(str);
83
            StringVect vect;
84
            splitToStringVector(vect, str, ' ');
85
            FOR_EACH (StringVectCIter, it, vect)
86
            {
87
                const std::string &flag = *it;
88
                if (flag == "mmx")
89
                    mCpuFlags |= FEATURE_MMX;
90
                else if (flag == "sse")
91
                    mCpuFlags |= FEATURE_SSE;
92
                else if (flag == "sse2")
93
                    mCpuFlags |= FEATURE_SSE2;
94
                else if (flag == "ssse3")
95
                    mCpuFlags |= FEATURE_SSSE3;
96
                else if (flag == "sse4_1")
97
                    mCpuFlags |= FEATURE_SSE4;
98
                else if (flag == "sse4_2")
99
                    mCpuFlags |= FEATURE_SSE42;
100
                else if (flag == "avx")
101
                    mCpuFlags |= FEATURE_AVX;
102
                else if (flag == "avx2")
103
                    mCpuFlags |= FEATURE_AVX2;
104
            }
105
            fclose(file);
106
            printFlags();
107
            return;
108
        }
109
    }
110
    fclose(file);
111
    if (logger != nullptr)
112
        logger->log("cpu features was not detected");
113
#else  // OTHER
114
115
#ifdef USE_SDL2
116
    if (SDL_HasMMX())
117
        mCpuFlags |= FEATURE_MMX;
118
    if (SDL_HasSSE())
119
        mCpuFlags |= FEATURE_SSE;
120
    if (SDL_HasSSE2())
121
        mCpuFlags |= FEATURE_SSE2;
122
    if (SDL_HasSSE3())
123
        mCpuFlags |= FEATURE_SSSE3;
124
    if (SDL_HasSSE41())
125
        mCpuFlags |= FEATURE_SSE4;
126
    if (SDL_HasSSE42())
127
        mCpuFlags |= FEATURE_SSE42;
128
129
#if SDL_VERSION_ATLEAST(2, 0, 2)
130
    if (SDL_HasAVX())
131
        mCpuFlags |= FEATURE_AVX;
132
#endif  // SDL_VERSION_ATLEAST(2, 0, 2)
133
#if SDL_VERSION_ATLEAST(2, 0, 4)
134
    if (SDL_HasAVX2())
135
        mCpuFlags |= FEATURE_AVX2;
136
#endif  // SDL_VERSION_ATLEAST(2, 0, 4)
137
138
    printFlags();
139
#else  // USE_SDL2
140
141
    if (logger)
142
        logger->log("cpu features not supported");
143
#endif  // USE_SDL2
144
#endif  // (defined(__amd64__) || defined(__i386__)) && defined(__GNUC__)
145
        // && (GCC_VERSION >= 40800) && !defined(ANDROID)
146
147
#if SDL_VERSION_ATLEAST(2, 0, 1)
148
    logger->log("System ram size: %d", SDL_GetSystemRAM());
149
#endif  // SDL_VERSION_ATLEAST(2, 0, 1)
150
1
}
151
152
1
void Cpu::printFlags()
153
{
154
1
    if (logger == nullptr)
155
        return;
156
3
    std::string str("CPU features:");
157
1
    if ((mCpuFlags & FEATURE_MMX) != 0U)
158
1
        str.append(" mmx");
159
1
    if ((mCpuFlags & FEATURE_SSE) != 0U)
160
1
        str.append(" sse");
161
1
    if ((mCpuFlags & FEATURE_SSE2) != 0U)
162
1
        str.append(" sse2");
163
1
    if ((mCpuFlags & FEATURE_SSSE3) != 0U)
164
1
        str.append(" ssse3");
165
1
    if ((mCpuFlags & FEATURE_SSE4) != 0U)
166
1
        str.append(" sse4");
167
1
    if ((mCpuFlags & FEATURE_SSE42) != 0U)
168
1
        str.append(" sse4_2");
169
1
    if ((mCpuFlags & FEATURE_AVX) != 0U)
170
1
        str.append(" avx");
171
1
    if ((mCpuFlags & FEATURE_AVX2) != 0U)
172
1
        str.append(" avx2");
173
1
    logger->log(str);
174
}
175
176
1
uint32_t Cpu::getFlags()
177
{
178
1
    return mCpuFlags;
179
}