| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | // ====================================================================== | ||
| 2 | // \title Os/Linux/Cpu.cpp | ||
| 3 | // \brief Linux implementation for Os::Cpu | ||
| 4 | // ====================================================================== | ||
| 5 | #include <unistd.h> | ||
| 6 | #include <Fw/Types/Assert.hpp> | ||
| 7 | #include <Fw/Types/StringUtils.hpp> | ||
| 8 | #include <Os/File.hpp> | ||
| 9 | #include <Os/Linux/Cpu.hpp> | ||
| 10 | #include <cstring> | ||
| 11 | namespace Os { | ||
| 12 | namespace Linux { | ||
| 13 | namespace Cpu { | ||
| 14 | |||
| 15 | // Proc FS /proc/stat file format example: | ||
| 16 | // | ||
| 17 | // cpu 270288 1598 88660 8470416 15185 9775 2990 867 0 0 | ||
| 18 | // cpu0 67462 108 22104 2118172 3779 2540 648 287 0 0 | ||
| 19 | // cpu1 74237 650 24059 2109680 2995 2447 667 93 0 0 | ||
| 20 | // cpu2 69388 630 22033 2115177 4428 2424 649 378 0 0 | ||
| 21 | // cpu3 59199 209 20462 2127387 3981 2363 1024 108 0 0 | ||
| 22 | // ... | ||
| 23 | |||
| 24 | // Needed format, and compliant with kernel < 2.5 | ||
| 25 | enum ProcCpuMeasures { CPU_NUMBER = 0, USER = 1, NICE = 2, SYSTEM = 3, IDLE = 4, MAX_CPU_TICK_TYPES = 8 }; | ||
| 26 | |||
| 27 | using ProcCpuData = FwSizeType[ProcCpuMeasures::MAX_CPU_TICK_TYPES]; | ||
| 28 | constexpr FwSizeType LINE_SIZE = 255; // log10(max(U64)) * 11 fields (kernel 2.6.33) = 220. Round to 256 - 1 (\0) | ||
| 29 | |||
| 30 | 940 | CpuInterface::Status getCpuData(FwSizeType cpu_index, ProcCpuData data) { | |
| 31 |
1/1✓ Branch 1 taken 940 times.
|
940 | Os::File file; |
| 32 | // Open the procfs file | ||
| 33 | 940 | constexpr char PROC_STAT_PATH[] = "/proc/stat"; | |
| 34 |
2/3✓ Branch 1 taken 940 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 940 times.
|
940 | if (file.open(PROC_STAT_PATH, Os::File::Mode::OPEN_READ) != Os::File::Status::OP_OK) { |
| 35 | ✗ | return CpuInterface::Status::ERROR; | |
| 36 | } | ||
| 37 | char proc_stat_line[LINE_SIZE + 1]; | ||
| 38 | // File starts with cpu line, then individual CPUs. | ||
| 39 | 940 | const FwSizeType line_count = cpu_index + 2; | |
| 40 |
2/2✓ Branch 0 taken 3290 times.
✓ Branch 1 taken 940 times.
|
4230 | for (FwSizeType i = 0; i < line_count; i++) { |
| 41 | 3290 | FwSizeType read_size = sizeof proc_stat_line - 1; | |
| 42 | Os::File::Status file_status = | ||
| 43 |
1/1✓ Branch 1 taken 3290 times.
|
3290 | file.readline(reinterpret_cast<U8*>(proc_stat_line), read_size, Os::File::WaitType::NO_WAIT); |
| 44 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3290 times.
|
3290 | if (file_status != Os::File::Status::OP_OK) { |
| 45 | ✗ | return CpuInterface::Status::ERROR; | |
| 46 | } | ||
| 47 | 3290 | proc_stat_line[read_size] = '\0'; // Null terminate, read_size is at most LINE_SIZE | |
| 48 | // Make sure we've not strayed passed the cpu section | ||
| 49 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3290 times.
|
3290 | if (::strncmp(proc_stat_line, "cpu", 3) != 0) { |
| 50 | ✗ | return CpuInterface::Status::ERROR; | |
| 51 | } | ||
| 52 | } | ||
| 53 | 940 | char* token_start = proc_stat_line + 3; // Length of "cpu" | |
| 54 |
2/2✓ Branch 0 taken 7520 times.
✓ Branch 1 taken 940 times.
|
8460 | for (FwSizeType i = 0; i < ProcCpuMeasures::MAX_CPU_TICK_TYPES; i++) { |
| 55 | 7520 | FwSizeType token = 0; | |
| 56 | 15040 | Fw::StringUtils::StringToNumberStatus status = Fw::StringUtils::string_to_number( | |
| 57 | token_start, | ||
| 58 |
1/1✓ Branch 1 taken 7520 times.
|
7520 | static_cast<FwSizeType>(sizeof proc_stat_line) - static_cast<FwSizeType>(token_start - proc_stat_line), |
| 59 | token, &token_start); | ||
| 60 | // Check conversion success | ||
| 61 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7520 times.
|
7520 | if (status != Fw::StringUtils::StringToNumberStatus::SUCCESSFUL_CONVERSION) { |
| 62 | ✗ | return CpuInterface::Status::ERROR; | |
| 63 | } | ||
| 64 | 7520 | data[i] = token; | |
| 65 | // Check cpu index is correct | ||
| 66 |
3/4✓ Branch 0 taken 940 times.
✓ Branch 1 taken 6580 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 940 times.
|
7520 | if (i == ProcCpuMeasures::CPU_NUMBER and data[i] != cpu_index) { |
| 67 | ✗ | return CpuInterface::Status::ERROR; | |
| 68 | } | ||
| 69 | } | ||
| 70 | 940 | return CpuInterface::Status::OP_OK; | |
| 71 | 940 | } | |
| 72 | |||
| 73 | 941 | CpuInterface::Status LinuxCpu::_getCount(FwSizeType& cpu_count) { | |
| 74 | 941 | long cpus = sysconf(_SC_NPROCESSORS_ONLN); | |
| 75 |
3/6✓ Branch 0 taken 941 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 941 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 941 times.
✗ Branch 6 not taken.
|
941 | if ((cpus > 0) && (static_cast<FwSizeType>(cpus) < std::numeric_limits<FwSizeType>::max())) { |
| 76 | 941 | cpu_count = static_cast<FwSizeType>(cpus); | |
| 77 | 941 | return Status::OP_OK; | |
| 78 | } | ||
| 79 | ✗ | cpu_count = 0; | |
| 80 | ✗ | return Status::ERROR; | |
| 81 | } | ||
| 82 | |||
| 83 | 940 | CpuInterface::Status LinuxCpu::_getTicks(Os::Cpu::Ticks& ticks, FwSizeType cpu_index) { | |
| 84 | 940 | FwSizeType count = 0; | |
| 85 |
1/1✓ Branch 1 taken 940 times.
|
940 | CpuInterface::Status status = this->_getCount(count); |
| 86 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 940 times.
|
940 | if (status != CpuInterface::Status::OP_OK) { |
| 87 | ✗ | return status; | |
| 88 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 940 times.
|
940 | } else if (cpu_index >= count) { |
| 89 | ✗ | return CpuInterface::Status::ERROR; | |
| 90 | } | ||
| 91 | 940 | ProcCpuData cpu_data = {0, 0, 0, 0, 0, 0, 0, 0}; | |
| 92 |
1/1✓ Branch 1 taken 940 times.
|
940 | status = getCpuData(cpu_index, cpu_data); |
| 93 | 940 | ticks.used = cpu_data[ProcCpuMeasures::USER] + cpu_data[ProcCpuMeasures::NICE] + cpu_data[ProcCpuMeasures::SYSTEM]; | |
| 94 | 940 | ticks.total = ticks.used + cpu_data[ProcCpuMeasures::IDLE]; | |
| 95 | |||
| 96 | 940 | return status; | |
| 97 | } | ||
| 98 | |||
| 99 | ✗ | CpuHandle* LinuxCpu::getHandle() { | |
| 100 | ✗ | return &this->m_handle; | |
| 101 | } | ||
| 102 | |||
| 103 | } // namespace Cpu | ||
| 104 | } // namespace Linux | ||
| 105 | } // namespace Os | ||
| 106 |