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

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