diff --git a/CMakeLists.txt b/CMakeLists.txt index 4d6e25150..dffa3f069 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -166,6 +166,7 @@ set(LIBFASTFETCH_SRC src/detection/title.c src/detection/host/host.c src/detection/os/os.c + src/detection/cpu/cpu.c src/detection/displayserver/displayServer.c src/detection/displayserver/wayland.c src/detection/displayserver/xcb.c @@ -216,16 +217,19 @@ if(APPLE) list(APPEND LIBFASTFETCH_SRC src/detection/host/host_apple.c src/detection/os/os_apple.c + src/detection/cpu/cpu_apple.c ) elseif(ANDROID) list(APPEND LIBFASTFETCH_SRC src/detection/host/host_android.c src/detection/os/os_android.c + src/detection/cpu/cpu_linux.c ) elseif(UNIX) list(APPEND LIBFASTFETCH_SRC src/detection/host/host_linux.c src/detection/os/os_linux.c + src/detection/cpu/cpu_linux.c ) else() message(FATAL_ERROR "Unsupported platform") diff --git a/presets/verbose b/presets/verbose index ff116bc0b..f4939d74b 100644 --- a/presets/verbose +++ b/presets/verbose @@ -17,7 +17,7 @@ --cursor-format "Theme: {}; Size: {}" --terminal-format "Process: {}; Path: {}; Exe: {}" --terminal-font-format "Raw: {}; Name: {}; Size: {}; Styles: {}; Pretty: {}" ---cpu-format "Name: {}; Pretty: {}; Vendor: {}; Logical online: {}; Logical configured: {}; Physical: {}; Cores: {}; temperature: {}; bios: {}; scaling max: {}; scaling min: {}; info max: {}; info min: {}; cpuinfo: {}; frequency: {}" +--cpu-format "Name: {}, Vendor: {}, CoresPhysical: {}, CoresLogical: {}, CoresOnline: {}, FrequencyMin: {}, FrequencyMax: {}, Temperature: {}" --cpu-usage-format "Percentage: {}" --gpu-format "Vendor: {}; Name: {}; Driver: {}; Temperature: {}" --memory-format "Percentage: {}; Used KiB: {}, Total KiB: {}, Used MiB: {}, Total MiB: {}, Used GiB: {}, Total GiB: {}" diff --git a/src/detection/cpu/cpu.c b/src/detection/cpu/cpu.c new file mode 100644 index 000000000..a30b31a27 --- /dev/null +++ b/src/detection/cpu/cpu.c @@ -0,0 +1,22 @@ +#include "cpu.h" +#include "detection/internal.h" + +void ffDetectCPUImpl(FFCPUResult* cpu); + +const FFCPUResult* ffDetectCPU() +{ + FF_DETECTION_INTERNAL_GUARD(FFCPUResult, + ffDetectCPUImpl(&result); + + const char* removeStrings[] = { + "(R)", "(r)", "(TM)", "(tm)", + " CPU", " FPU", " APU", " Processor", + " Dual-Core", " Quad-Core", " Six-Core", " Eight-Core", " Ten-Core", + " 2-Core", " 4-Core", " 6-Core", " 8-Core", " 10-Core", " 12-Core", " 14-Core", " 16-Core", + " with Radeon Graphics" + }; + ffStrbufRemoveStringsA(&result.name, sizeof(removeStrings) / sizeof(removeStrings[0]), removeStrings); + ffStrbufSubstrBeforeFirstC(&result.name, '@'); //Cut the speed output in the name as we append our own + ffStrbufTrimRight(&result.name, ' '); //If we removed the @ in previous step there was most likely a space before it + ); +} diff --git a/src/detection/cpu/cpu.h b/src/detection/cpu/cpu.h new file mode 100644 index 000000000..e207c97bb --- /dev/null +++ b/src/detection/cpu/cpu.h @@ -0,0 +1,27 @@ +#pragma once + +#ifndef FF_INCLUDED_detection_cpu_cpu +#define FF_INCLUDED_detection_cpu_cpu + +#include "fastfetch.h" + +#define FF_CPU_TEMP_UNSET (0/0.0) + +typedef struct FFCPUResult +{ + FFstrbuf name; + FFstrbuf vendor; + + uint16_t coresPhysical; + uint16_t coresLogical; + uint16_t coresOnline; + + double frequencyMin; + double frequencyMax; + + double temperature; +} FFCPUResult; + +const FFCPUResult* ffDetectCPU(); + +#endif diff --git a/src/detection/cpu/cpu_apple.c b/src/detection/cpu/cpu_apple.c new file mode 100644 index 000000000..b5b89e8e9 --- /dev/null +++ b/src/detection/cpu/cpu_apple.c @@ -0,0 +1,17 @@ +#include "cpu.h" + +void ffDetectCPUImpl(FFCPUResult* cpu) +{ + ffStrbufInit(&cpu->name); + ffStrbufInit(&cpu->vendor); + + cpu->coresPhysical = 0; + cpu->coresLogical = 0; + cpu->coresOnline = 0; + + cpu->frequencyCurrent = 0.0; + cpu->frequencyMin = 0.0; + cpu->frequencyMax = 0.0; + + cpu->temperature = FF_CPU_TEMP_UNKNOWN; +} diff --git a/src/detection/cpu/cpu_linux.c b/src/detection/cpu/cpu_linux.c new file mode 100644 index 000000000..a56a25d0c --- /dev/null +++ b/src/detection/cpu/cpu_linux.c @@ -0,0 +1,102 @@ +#include "cpu.h" +#include "common/io.h" +#include "common/properties.h" +#include "detection/temps.h" + +#include +#include + +static void parseCpuInfo(FFCPUResult* cpu, FFstrbuf* physicalCoresBuffer) +{ + FILE* cpuinfo = fopen("/proc/cpuinfo", "r"); + if(cpuinfo == NULL) + return; + + char* line = NULL; + size_t len = 0; + + while(getline(&line, &len, cpuinfo) != -1) + { + //Stop after the first CPU + if(cpu->name.length > 0 && (*line == '\0' || *line == '\n')) + break; + + (void)( + ffParsePropLine(line, "model name :", &cpu->name) || + ffParsePropLine(line, "vendor_id :", &cpu->vendor) || + ffParsePropLine(line, "cpu cores :", physicalCoresBuffer) || + (cpu->name.length == 0 && ffParsePropLine(line, "Hardware :", &cpu->name)) //For Android devices + ); + } + + if(line != NULL) + free(line); + + fclose(cpuinfo); +} + +static double getGHz(const char* file) +{ + FFstrbuf content; + ffStrbufInit(&content); + ffReadFileBuffer(file, &content); + double herz = ffStrbufToDouble(&content); + ffStrbufDestroy(&content); + + //ffStrbufToDouble failed + if(herz != herz) + return 0; + + herz /= 1000.0; //to MHz + return herz / 1000.0; //to GHz +} + +static double getFrequency(const char* info, const char* scaling) +{ + double frequency = getGHz(info); + if(frequency > 0.0) + return frequency; + + return getGHz(scaling); +} + +static double detectCPUTemp() +{ + const FFTempsResult *temps = ffDetectTemps(); + + for(uint32_t i = 0; i < temps->values.length; i++) + { + FFTempValue* value = ffListGet(&temps->values, i); + + if( + ffStrbufFirstIndexS(&value->name, "cpu") < value->name.length || + ffStrbufCompS(&value->name, "k10temp") == 0 || + ffStrbufCompS(&value->name, "coretemp") == 0 + ) return value->value; + } + + return FF_CPU_TEMP_UNSET; +} + +void ffDetectCPUImpl(FFCPUResult* cpu) +{ + ffStrbufInit(&cpu->name); + ffStrbufInit(&cpu->vendor); + + FFstrbuf physicalCoresBuffer; + ffStrbufInit(&physicalCoresBuffer); + + parseCpuInfo(cpu, &physicalCoresBuffer); + + cpu->coresPhysical = ffStrbufToUInt16(&physicalCoresBuffer, 1); + cpu->coresLogical = (uint16_t) get_nprocs_conf(); + cpu->coresOnline = (uint16_t) get_nprocs(); + + #define BP "/sys/devices/system/cpu/cpufreq/policy0/" + cpu->frequencyMin = getFrequency(BP"cpuinfo_min_freq", BP"scaling_min_freq"); + cpu->frequencyMax = getFrequency(BP"cpuinfo_max_freq", BP"scaling_max_freq"); + + cpu->temperature = detectCPUTemp(); + + ffStrbufDestroy(&physicalCoresBuffer); +} diff --git a/src/detection/host/host.c b/src/detection/host/host.c index cc8038d8a..ea8274dbe 100644 --- a/src/detection/host/host.c +++ b/src/detection/host/host.c @@ -1,25 +1,11 @@ #include "host.h" - -#include "pthread.h" +#include "detection/internal.h" void ffDetectHostImpl(FFHostResult* host); const FFHostResult* ffDetectHost() { - static FFHostResult host; - - static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; - static bool init = false; - pthread_mutex_lock(&mutex); - if(init) - { - pthread_mutex_unlock(&mutex); - return &host; - } - init = true; - - ffDetectHostImpl(&host); - - pthread_mutex_unlock(&mutex); - return &host; + FF_DETECTION_INTERNAL_GUARD(FFHostResult, + ffDetectHostImpl(&result) + ); } diff --git a/src/detection/host/host.h b/src/detection/host/host.h index 4352cf766..cdf2fbf53 100644 --- a/src/detection/host/host.h +++ b/src/detection/host/host.h @@ -1,7 +1,7 @@ #pragma once -#ifndef FF_INCLUDED_DETECTION_HOST_host -#define FF_INCLUDED_DETECTION_HOST_host +#ifndef FF_INCLUDED_detection_host_host +#define FF_INCLUDED_detection_host_host #include "fastfetch.h" diff --git a/src/detection/internal.h b/src/detection/internal.h new file mode 100644 index 000000000..f4dc67cbb --- /dev/null +++ b/src/detection/internal.h @@ -0,0 +1,23 @@ +#pragma once + +#ifndef FF_INCLUDED_detection_internal +#define FF_INCLUDED_detection_internal + +#include "pthread.h" + +#define FF_DETECTION_INTERNAL_GUARD(ResultType, ...) \ + static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; \ + static ResultType result; \ + static bool init = false; \ + pthread_mutex_lock(&mutex); \ + if(init) \ + { \ + pthread_mutex_unlock(&mutex); \ + return &result; \ + } \ + init = true; \ + __VA_ARGS__; \ + pthread_mutex_unlock(&mutex); \ + return &result; \ + +#endif diff --git a/src/detection/os/os.c b/src/detection/os/os.c index e8ecb44cf..dee22a566 100644 --- a/src/detection/os/os.c +++ b/src/detection/os/os.c @@ -1,24 +1,11 @@ #include "os.h" - -#include +#include "detection/internal.h" void ffDetectOSImpl(FFOSResult* os, const FFinstance* instance); const FFOSResult* ffDetectOS(const FFinstance* instance) { - static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; - static FFOSResult result; - static bool init = false; - pthread_mutex_lock(&mutex); - if(init) - { - pthread_mutex_unlock(&mutex); - return &result; - } - init = true; - - ffDetectOSImpl(&result, instance); - - pthread_mutex_unlock(&mutex); - return &result; + FF_DETECTION_INTERNAL_GUARD(FFOSResult, + ffDetectOSImpl(&result, instance) + ); } diff --git a/src/detection/os/os.h b/src/detection/os/os.h index 1e2224663..688d6f63b 100644 --- a/src/detection/os/os.h +++ b/src/detection/os/os.h @@ -1,7 +1,7 @@ #pragma once -#ifndef FF_INCLUDED_detection_os -#define FF_INCLUDED_detection_os +#ifndef FF_INCLUDED_detection_os_os +#define FF_INCLUDED_detection_os_os #include "fastfetch.h" diff --git a/src/modules/cpu.c b/src/modules/cpu.c index c058ac140..e7566f63a 100644 --- a/src/modules/cpu.c +++ b/src/modules/cpu.c @@ -1,219 +1,51 @@ #include "fastfetch.h" -#include "common/io.h" -#include "common/properties.h" #include "common/printing.h" #include "common/caching.h" -#include "detection/temps.h" - -#include +#include "detection/cpu/cpu.h" #define FF_CPU_MODULE_NAME "CPU" -#define FF_CPU_NUM_FORMAT_ARGS 15 - -static double getGhz(const char* policyFile, const char* cpuFile) -{ - FFstrbuf content; - ffStrbufInit(&content); - - ffReadFileBuffer(policyFile, &content); - if(content.length == 0) - ffReadFileBuffer(cpuFile, &content); - - double herz = ffStrbufToDouble(&content); - - ffStrbufDestroy(&content); - - //ffStrbufToDouble failed - if(herz != herz) - return 0; - - herz /= 1000.0; //to MHz - return herz / 1000.0; //to GHz -} - -static double detectCPUTemp() -{ - const FFTempsResult *temps = ffDetectTemps(); - - for(uint32_t i = 0; i < temps->values.length; i++) - { - FFTempValue* value = ffListGet(&temps->values, i); - - if( - ffStrbufFirstIndexS(&value->name, "cpu") < value->name.length || - ffStrbufCompS(&value->name, "k10temp") == 0 || - ffStrbufCompS(&value->name, "coretemp") == 0 - ) return value->value; - } - - return 0.0 / 0.0; //NaN -} +#define FF_CPU_NUM_FORMAT_ARGS 8 void ffPrintCPU(FFinstance* instance) { if(ffPrintFromCache(instance, FF_CPU_MODULE_NAME, &instance->config.cpu, FF_CPU_NUM_FORMAT_ARGS)) return; - FILE* cpuinfo = fopen("/proc/cpuinfo", "r"); - if(cpuinfo == NULL) + const FFCPUResult* cpu = ffDetectCPU(); + + if(cpu->vendor.length == 0 && cpu->name.length == 0 && cpu->coresOnline == 0) { - ffPrintError(instance, FF_CPU_MODULE_NAME, 0, &instance->config.cpu, "fopen(\"""/proc/cpuinfo\", \"r\") == NULL"); + ffPrintError(instance, FF_CPU_MODULE_NAME, 0, &instance->config.cpu, "No CPU detected"); return; } - FFstrbuf name; - ffStrbufInitA(&name, 64); + FFstrbuf output; + ffStrbufInitA(&output, 128); - FFstrbuf vendor; - ffStrbufInitA(&vendor, 64); - - FFstrbuf physicalCoresString; - ffStrbufInit(&physicalCoresString); - - FFstrbuf procGhzString; - ffStrbufInit(&procGhzString); - - char* line = NULL; - size_t len = 0; - - while(getline(&line, &len, cpuinfo) != -1) + if(cpu->name.length > 0) + ffStrbufAppend(&output, &cpu->name); + else if(cpu->vendor.length > 0) { - //Stop after the first CPU - if(name.length > 0 && (*line == '\0' || *line == '\n')) - break; - - (void)( - ffParsePropLine(line, "model name :", &name) || - ffParsePropLine(line, "vendor_id :", &vendor) || - ffParsePropLine(line, "cpu cores :", &physicalCoresString) || - ffParsePropLine(line, "cpu MHz :", &procGhzString) || - (name.length == 0 && ffParsePropLine(line, "Hardware :", &name)) //For Android devices - ); - } - - if(line != NULL) - free(line); - - fclose(cpuinfo); - - double procGhz = ffStrbufToDouble(&procGhzString); - if(procGhz != procGhz) - procGhz = 0; //NaN - else - procGhz /= 1000.0; //To GHz - - ffStrbufDestroy(&procGhzString); - - double biosLimit = getGhz("/sys/devices/system/cpu/cpufreq/policy0/bios_limit", "/sys/devices/system/cpu/cpu0/cpufreq/bios_limit"); - double scalingMaxFreq = getGhz("/sys/devices/system/cpu/cpufreq/policy0/scaling_max_freq", "/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq"); - double scalingMinFreq = getGhz("/sys/devices/system/cpu/cpufreq/policy0/scaling_min_freq", "/sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq"); - double infoMaxFreq = getGhz("/sys/devices/system/cpu/cpufreq/policy0/cpuinfo_max_freq", "/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq"); - double infoMinFreq = getGhz("/sys/devices/system/cpu/cpufreq/policy0/cpuinfo_min_freq", "/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_min_freq"); - - #if FF_HAVE_SYSINFO_H - int numProcsOnline = get_nprocs(); - int numProcsAvailable = get_nprocs_conf(); - #else - int numProcsOnline = 0; - int numProcsAvailable = 0; - #endif - - int physicalCores = 1; - sscanf(physicalCoresString.chars, "%i", &physicalCores); - ffStrbufDestroy(&physicalCoresString); - - //The current get_nprocs* returns 1 on failure. It also makes no sense to have a (1) as count - int numProcs = numProcsOnline; - if(numProcs <= 1) - numProcs = numProcsAvailable; - if(numProcs <= 1) - numProcs = physicalCores; - - double ghz = biosLimit; - if(ghz == 0) - ghz = scalingMaxFreq; - if(ghz == 0) - ghz = infoMaxFreq; - if(ghz == 0) - ghz = procGhz; - if(ghz == 0) - ghz = scalingMinFreq; - if(ghz == 0) - ghz = infoMinFreq; - - if( - name.length == 0 && - vendor.length == 0 && - numProcs <= 1 && - ghz <= 0 - ) { - ffStrbufDestroy(&name); - ffStrbufDestroy(&vendor); - ffPrintError(instance, FF_CPU_MODULE_NAME, 0, &instance->config.cpu, "No CPU info found in /proc/cpuinfo"); - return; - } - - FFstrbuf namePretty; - ffStrbufInitA(&namePretty, 64); - ffStrbufAppend(&namePretty, &name); - - const char* removeStrings[] = { - "(R)", "(r)", "(TM)", "(tm)", - " CPU", " FPU", " APU", " Processor", - " Dual-Core", " Quad-Core", " Six-Core", " Eight-Core", " Ten-Core", - " 2-Core", " 4-Core", " 6-Core", " 8-Core", " 10-Core", " 12-Core", " 14-Core", " 16-Core", - " with Radeon Graphics" - }; - - ffStrbufRemoveStringsA(&namePretty, sizeof(removeStrings) / sizeof(removeStrings[0]), removeStrings); - ffStrbufSubstrBeforeFirstC(&namePretty, '@'); //Cut the speed output in the name as we append our own - ffStrbufTrimRight(&namePretty, ' '); //If we removed the @ in previous step there was most likely a space before it - - double cpuTemp; - if(instance->config.cpu.outputFormat.length > 0) - cpuTemp = detectCPUTemp(); - - FFstrbuf cpu; - ffStrbufInitA(&cpu, 128); - - if(namePretty.length > 0) - ffStrbufAppend(&cpu, &namePretty); - else if(name.length > 0) - ffStrbufAppend(&cpu, &name); - else if(vendor.length > 0) - { - ffStrbufAppend(&cpu, &vendor); - ffStrbufAppendS(&cpu, " CPU"); + ffStrbufAppend(&output, &cpu->vendor); + ffStrbufAppendS(&output, " CPU"); } else - ffStrbufAppendS(&cpu, "CPU"); + ffStrbufAppendS(&output, "CPU"); - if(numProcs > 1) - ffStrbufAppendF(&cpu, " (%i)", numProcs); + if(cpu->coresOnline > 1) + ffStrbufAppendF(&output, " (%u)", cpu->coresOnline); - if(ghz > 0) - ffStrbufAppendF(&cpu, " @ %.9gGHz", ghz); + if(cpu->frequencyMax > 0.0) + ffStrbufAppendF(&output, " @ %.9gGHz", cpu->frequencyMax); - ffPrintAndWriteToCache(instance, FF_CPU_MODULE_NAME, &instance->config.cpu, &cpu, FF_CPU_NUM_FORMAT_ARGS, (FFformatarg[]){ - {FF_FORMAT_ARG_TYPE_STRBUF, &name}, - {FF_FORMAT_ARG_TYPE_STRBUF, &namePretty}, - {FF_FORMAT_ARG_TYPE_STRBUF, &vendor}, - {FF_FORMAT_ARG_TYPE_INT, &numProcsOnline}, - {FF_FORMAT_ARG_TYPE_INT, &numProcsAvailable}, - {FF_FORMAT_ARG_TYPE_INT, &physicalCores}, - {FF_FORMAT_ARG_TYPE_INT, &numProcs}, - {FF_FORMAT_ARG_TYPE_DOUBLE, &cpuTemp}, - {FF_FORMAT_ARG_TYPE_DOUBLE, &biosLimit}, - {FF_FORMAT_ARG_TYPE_DOUBLE, &scalingMaxFreq}, - {FF_FORMAT_ARG_TYPE_DOUBLE, &scalingMinFreq}, - {FF_FORMAT_ARG_TYPE_DOUBLE, &infoMaxFreq}, - {FF_FORMAT_ARG_TYPE_DOUBLE, &infoMinFreq}, - {FF_FORMAT_ARG_TYPE_DOUBLE, &procGhz}, - {FF_FORMAT_ARG_TYPE_DOUBLE, &ghz} + ffPrintAndWriteToCache(instance, FF_CPU_MODULE_NAME, &instance->config.cpu, &output, FF_CPU_NUM_FORMAT_ARGS, (FFformatarg[]){ + {FF_FORMAT_ARG_TYPE_STRBUF, &cpu->name}, + {FF_FORMAT_ARG_TYPE_STRBUF, &cpu->vendor}, + {FF_FORMAT_ARG_TYPE_UINT16, &cpu->coresPhysical}, + {FF_FORMAT_ARG_TYPE_UINT16, &cpu->coresLogical}, + {FF_FORMAT_ARG_TYPE_UINT16, &cpu->coresOnline}, + {FF_FORMAT_ARG_TYPE_DOUBLE, &cpu->frequencyMin}, + {FF_FORMAT_ARG_TYPE_DOUBLE, &cpu->frequencyMax}, + {FF_FORMAT_ARG_TYPE_DOUBLE, &cpu->temperature} }); - - ffStrbufDestroy(&cpu); - ffStrbufDestroy(&namePretty); - ffStrbufDestroy(&name); - ffStrbufDestroy(&vendor); } diff --git a/src/util/FFstrbuf.c b/src/util/FFstrbuf.c index adca0dc11..09006e7c1 100644 --- a/src/util/FFstrbuf.c +++ b/src/util/FFstrbuf.c @@ -3,6 +3,7 @@ #include #include #include +#include static char* CHAR_NULL_PTR = ""; @@ -553,6 +554,15 @@ double ffStrbufToDouble(const FFstrbuf* strbuf) return value; } +uint16_t ffStrbufToUInt16(const FFstrbuf* strbuf, uint16_t defaultValue) +{ + uint16_t value; + if(sscanf(strbuf->chars, "%"SCNu16, &value) != 1) + return defaultValue; + + return value; +} + void ffStrbufDestroy(FFstrbuf* strbuf) { free(strbuf->chars); diff --git a/src/util/FFstrbuf.h b/src/util/FFstrbuf.h index 5b7a251c5..0dec7cd40 100644 --- a/src/util/FFstrbuf.h +++ b/src/util/FFstrbuf.h @@ -99,6 +99,7 @@ void ffStrbufWriteTo(const FFstrbuf* strbuf, FILE* file); void ffStrbufPutTo(const FFstrbuf* strbuf, FILE* file); double ffStrbufToDouble(const FFstrbuf* strbuf); +uint16_t ffStrbufToUInt16(const FFstrbuf* strbuf, uint16_t defaultValue); void ffStrbufDestroy(FFstrbuf* strbuf);