1 /*
2  *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 #include "cpu_linux.h"
12 
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <unistd.h>
17 
18 namespace webrtc {
CpuLinux()19 CpuLinux::CpuLinux()
20     : m_oldBusyTime(0),
21       m_oldIdleTime(0),
22       m_oldBusyTimeMulti(NULL),
23       m_oldIdleTimeMulti(NULL),
24       m_idleArray(NULL),
25       m_busyArray(NULL),
26       m_resultArray(NULL),
27       m_numCores(0) {
28     const int result = GetNumCores();
29     if (result != -1) {
30       m_numCores = result;
31       m_oldBusyTimeMulti = new long long[m_numCores];
32       memset(m_oldBusyTimeMulti, 0, sizeof(long long) * m_numCores);
33       m_oldIdleTimeMulti = new long long[m_numCores];
34       memset(m_oldIdleTimeMulti, 0, sizeof(long long) * m_numCores);
35       m_idleArray = new long long[m_numCores];
36       memset(m_idleArray, 0, sizeof(long long) * m_numCores);
37       m_busyArray = new long long[m_numCores];
38       memset(m_busyArray, 0, sizeof(long long) * m_numCores);
39       m_resultArray = new WebRtc_UWord32[m_numCores];
40 
41       GetData(m_oldBusyTime, m_oldIdleTime, m_busyArray, m_idleArray);
42     }
43 }
44 
~CpuLinux()45 CpuLinux::~CpuLinux()
46 {
47     delete [] m_oldBusyTimeMulti;
48     delete [] m_oldIdleTimeMulti;
49     delete [] m_idleArray;
50     delete [] m_busyArray;
51     delete [] m_resultArray;
52 }
53 
CpuUsage()54 WebRtc_Word32 CpuLinux::CpuUsage()
55 {
56     WebRtc_UWord32 dummy = 0;
57     WebRtc_UWord32* dummyArray = NULL;
58     return CpuUsageMultiCore(dummy, dummyArray);
59 }
60 
CpuUsageMultiCore(WebRtc_UWord32 & numCores,WebRtc_UWord32 * & coreArray)61 WebRtc_Word32 CpuLinux::CpuUsageMultiCore(WebRtc_UWord32& numCores,
62                                           WebRtc_UWord32*& coreArray)
63 {
64     coreArray = m_resultArray;
65     numCores = m_numCores;
66     long long busy = 0;
67     long long idle = 0;
68     if (GetData(busy, idle, m_busyArray, m_idleArray) != 0)
69         return -1;
70 
71     long long deltaBusy = busy - m_oldBusyTime;
72     long long deltaIdle = idle - m_oldIdleTime;
73     m_oldBusyTime = busy;
74     m_oldIdleTime = idle;
75 
76     int retVal = -1;
77     if (deltaBusy + deltaIdle == 0)
78     {
79         retVal = 0;
80     }
81     else
82     {
83         retVal = (int)(100 * (deltaBusy) / (deltaBusy + deltaIdle));
84     }
85 
86     if (coreArray == NULL)
87     {
88       return retVal;
89     }
90 
91     for (WebRtc_UWord32 i = 0; i < m_numCores; i++)
92     {
93         deltaBusy = m_busyArray[i] - m_oldBusyTimeMulti[i];
94         deltaIdle = m_idleArray[i] - m_oldIdleTimeMulti[i];
95         m_oldBusyTimeMulti[i] = m_busyArray[i];
96         m_oldIdleTimeMulti[i] = m_idleArray[i];
97         if(deltaBusy + deltaIdle == 0)
98         {
99             coreArray[i] = 0;
100         }
101         else
102         {
103             coreArray[i] = (int)(100 * (deltaBusy) / (deltaBusy+deltaIdle));
104         }
105     }
106     return retVal;
107 }
108 
109 
GetData(long long & busy,long long & idle,long long * & busyArray,long long * & idleArray)110 int CpuLinux::GetData(long long& busy, long long& idle, long long*& busyArray,
111                       long long*& idleArray)
112 {
113     FILE* fp = fopen("/proc/stat", "r");
114     if (!fp)
115     {
116         return -1;
117     }
118 
119     char line[100];
120     if (fgets(line, 100, fp) == NULL) {
121         fclose(fp);
122         return -1;
123     }
124     char firstWord[100];
125     if (sscanf(line, "%s ", firstWord) != 1) {
126         fclose(fp);
127         return -1;
128     }
129     if (strncmp(firstWord, "cpu", 3) != 0) {
130         fclose(fp);
131         return -1;
132     }
133     char sUser[100];
134     char sNice[100];
135     char sSystem[100];
136     char sIdle[100];
137     if (sscanf(line, "%s %s %s %s %s ",
138                firstWord, sUser, sNice, sSystem, sIdle) != 5) {
139         fclose(fp);
140         return -1;
141     }
142     long long luser = atoll(sUser);
143     long long lnice = atoll(sNice);
144     long long lsystem = atoll(sSystem);
145     long long lidle = atoll (sIdle);
146 
147     busy = luser + lnice + lsystem;
148     idle = lidle;
149     for (WebRtc_UWord32 i = 0; i < m_numCores; i++)
150     {
151         if (fgets(line, 100, fp) == NULL) {
152             fclose(fp);
153             return -1;
154         }
155         if (sscanf(line, "%s %s %s %s %s ", firstWord, sUser, sNice, sSystem,
156                    sIdle) != 5) {
157             fclose(fp);
158             return -1;
159         }
160         luser = atoll(sUser);
161         lnice = atoll(sNice);
162         lsystem = atoll(sSystem);
163         lidle = atoll (sIdle);
164         busyArray[i] = luser + lnice + lsystem;
165         idleArray[i] = lidle;
166     }
167     fclose(fp);
168     return 0;
169 }
170 
GetNumCores()171 int CpuLinux::GetNumCores()
172 {
173     FILE* fp = fopen("/proc/stat", "r");
174     if (!fp)
175     {
176         return -1;
177     }
178     // Skip first line
179     char line[100];
180     if (!fgets(line, 100, fp))
181     {
182         fclose(fp);
183         return -1;
184     }
185     int numCores = -1;
186     char firstWord[100];
187     do
188     {
189         numCores++;
190         if (fgets(line, 100, fp))
191         {
192             if (sscanf(line, "%s ", firstWord) != 1) {
193                 firstWord[0] = '\0';
194             }
195         } else {
196             break;
197         }
198     } while (strncmp(firstWord, "cpu", 3) == 0);
199     fclose(fp);
200     return numCores;
201 }
202 } // namespace webrtc
203