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_mac.h"
12
13#include <iostream>
14#include <mach/mach.h>
15#include <mach/mach_error.h>
16
17#include "tick_util.h"
18
19namespace webrtc {
20CpuWrapperMac::CpuWrapperMac()
21    : _cpuCount(0),
22      _cpuUsage(NULL),
23      _totalCpuUsage(0),
24      _lastTickCount(NULL),
25      _lastTime(0)
26{
27    natural_t cpuCount;
28    processor_info_array_t infoArray;
29    mach_msg_type_number_t infoCount;
30
31    kern_return_t error = host_processor_info(mach_host_self(),
32                                              PROCESSOR_CPU_LOAD_INFO,
33                                              &cpuCount,
34                                              &infoArray,
35                                              &infoCount);
36    if (error)
37    {
38        return;
39    }
40
41    _cpuCount = cpuCount;
42    _cpuUsage = new WebRtc_UWord32[cpuCount];
43    _lastTickCount = new WebRtc_Word64[cpuCount];
44    _lastTime = TickTime::MillisecondTimestamp();
45
46    processor_cpu_load_info_data_t* cpuLoadInfo =
47        (processor_cpu_load_info_data_t*) infoArray;
48    for (unsigned int cpu= 0; cpu < cpuCount; cpu++)
49    {
50        WebRtc_Word64 ticks = 0;
51        for (int state = 0; state < 2; state++)
52        {
53            ticks += cpuLoadInfo[cpu].cpu_ticks[state];
54        }
55        _lastTickCount[cpu] = ticks;
56        _cpuUsage[cpu] = 0;
57    }
58    vm_deallocate(mach_task_self(), (vm_address_t)infoArray, infoCount);
59}
60
61CpuWrapperMac::~CpuWrapperMac()
62{
63    delete[] _cpuUsage;
64    delete[] _lastTickCount;
65}
66
67WebRtc_Word32 CpuWrapperMac::CpuUsage()
68{
69    WebRtc_UWord32 numCores;
70    WebRtc_UWord32* array = NULL;
71    return CpuUsageMultiCore(numCores, array);
72}
73
74WebRtc_Word32
75CpuWrapperMac::CpuUsageMultiCore(WebRtc_UWord32& numCores,
76                                 WebRtc_UWord32*& array)
77{
78    // sanity check
79    if(_cpuUsage == NULL)
80    {
81        return -1;
82    }
83
84    WebRtc_Word64 now = TickTime::MillisecondTimestamp();
85    WebRtc_Word64 timeDiffMS = now - _lastTime;
86    if(timeDiffMS >= 500)
87    {
88        if(Update(timeDiffMS) != 0)
89        {
90           return -1;
91        }
92        _lastTime = now;
93    }
94
95    numCores = _cpuCount;
96    array = _cpuUsage;
97    return _totalCpuUsage / _cpuCount;
98}
99
100WebRtc_Word32 CpuWrapperMac::Update(WebRtc_Word64 timeDiffMS)
101{
102    natural_t cpuCount;
103    processor_info_array_t infoArray;
104    mach_msg_type_number_t infoCount;
105
106    kern_return_t error = host_processor_info(mach_host_self(),
107                                              PROCESSOR_CPU_LOAD_INFO,
108                                              &cpuCount,
109                                              &infoArray,
110                                              &infoCount);
111    if (error)
112    {
113        return -1;
114    }
115
116    processor_cpu_load_info_data_t* cpuLoadInfo =
117        (processor_cpu_load_info_data_t*) infoArray;
118
119    _totalCpuUsage = 0;
120    for (unsigned int cpu = 0; cpu < cpuCount; cpu++)
121    {
122        WebRtc_Word64 ticks = 0;
123        for (int state = 0; state < 2; state++)
124        {
125            ticks += cpuLoadInfo[cpu].cpu_ticks[state];
126        }
127        if(timeDiffMS <= 0)
128        {
129            _cpuUsage[cpu] = 0;
130        }else {
131            _cpuUsage[cpu] = (WebRtc_UWord32)((1000 *
132                                              (ticks - _lastTickCount[cpu])) /
133                                              timeDiffMS);
134        }
135        _lastTickCount[cpu] = ticks;
136        _totalCpuUsage += _cpuUsage[cpu];
137    }
138
139    vm_deallocate(mach_task_self(), (vm_address_t)infoArray, infoCount);
140
141    return 0;
142}
143} // namespace webrtc
144