VirtualBox

source: vbox/trunk/src/VBox/Runtime/r3/linux/mp-linux.cpp@ 19167

Last change on this file since 19167 was 15399, checked in by vboxsync, 16 years ago

iprt: new Linux sysfs APIs

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 6.4 KB
Line 
1/* $Id: mp-linux.cpp 15399 2008-12-12 22:02:14Z vboxsync $ */
2/** @file
3 * IPRT - Multiprocessor, Linux.
4 */
5
6/*
7 * Copyright (C) 2006-2008 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 *
26 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
27 * Clara, CA 95054 USA or visit http://www.sun.com if you need
28 * additional information or have any questions.
29 */
30
31
32/*******************************************************************************
33* Header Files *
34*******************************************************************************/
35#define LOG_GROUP RTLOGGROUP_SYSTEM
36#include <stdio.h>
37#include <errno.h>
38
39#include <iprt/mp.h>
40#include <iprt/cpuset.h>
41#include <iprt/assert.h>
42#include <iprt/string.h>
43#include <iprt/linux/sysfs.h>
44
45
46/**
47 * Internal worker that determins the max possible CPU count.
48 *
49 * @returns Max cpus.
50 */
51static RTCPUID rtMpLinuxMaxCpus(void)
52{
53#if 0 /* this doesn't do the right thing :-/ */
54 int cMax = sysconf(_SC_NPROCESSORS_CONF);
55 Assert(cMax >= 1);
56 return cMax;
57#else
58 static uint32_t s_cMax = 0;
59 if (!s_cMax)
60 {
61 int cMax = 1;
62 for (unsigned iCpu = 0; iCpu < RTCPUSET_MAX_CPUS; iCpu++)
63 if (RTLinuxSysFsExists("devices/system/cpu/cpu%d", iCpu))
64 cMax = iCpu + 1;
65 ASMAtomicUoWriteU32((uint32_t volatile *)&s_cMax, cMax);
66 return cMax;
67 }
68 return s_cMax;
69#endif
70}
71
72/**
73 * Internal worker that picks the processor speed in MHz from /proc/cpuinfo.
74 *
75 * @returns CPU frequency.
76 */
77static uint32_t rtMpLinuxGetFrequency(RTCPUID idCpu)
78{
79 FILE *pFile = fopen("/proc/cpuinfo", "r");
80 if (!pFile)
81 return 0;
82
83 char sz[256];
84 RTCPUID idCpuFound = NIL_RTCPUID;
85 uint32_t Frequency = 0;
86 while (fgets(sz, sizeof(sz), pFile))
87 {
88 char *psz;
89 if ( !strncmp(sz, "processor", 9)
90 && (sz[10] == ' ' || sz[10] == '\t' || sz[10] == ':')
91 && (psz = strchr(sz, ':')))
92 {
93 psz += 2;
94 int64_t iCpu;
95 int rc = RTStrToInt64Ex(psz, NULL, 0, &iCpu);
96 if (RT_SUCCESS(rc))
97 idCpuFound = iCpu;
98 }
99 else if ( idCpu == idCpuFound
100 && !strncmp(sz, "cpu MHz", 7)
101 && (sz[10] == ' ' || sz[10] == '\t' || sz[10] == ':')
102 && (psz = strchr(sz, ':')))
103 {
104 psz += 2;
105 int64_t v;
106 int rc = RTStrToInt64Ex(psz, &psz, 0, &v);
107 if (RT_SUCCESS(rc))
108 {
109 Frequency = v;
110 break;
111 }
112 }
113 }
114 fclose(pFile);
115 return Frequency;
116}
117
118
119/** @todo RTmpCpuId(). */
120
121RTDECL(int) RTMpCpuIdToSetIndex(RTCPUID idCpu)
122{
123 return idCpu < rtMpLinuxMaxCpus() ? idCpu : -1;
124}
125
126
127RTDECL(RTCPUID) RTMpCpuIdFromSetIndex(int iCpu)
128{
129 return (unsigned)iCpu < rtMpLinuxMaxCpus() ? iCpu : NIL_RTCPUID;
130}
131
132
133RTDECL(RTCPUID) RTMpGetMaxCpuId(void)
134{
135 return rtMpLinuxMaxCpus() - 1;
136}
137
138
139RTDECL(bool) RTMpIsCpuOnline(RTCPUID idCpu)
140{
141 /** @todo check if there is a simpler interface than this... */
142 int i = RTLinuxSysFsReadIntFile(0, "devices/system/cpu/cpu%d/online", (int)idCpu);
143 if ( i == -1
144 && RTLinuxSysFsExists("devices/system/cpu/cpu%d", (int)idCpu))
145 {
146 Assert(!RTLinuxSysFsExists("devices/system/cpu/cpu%d/online", (int)idCpu));
147 i = 1;
148 }
149
150 Assert(i == 0 || i == -1 || i == 1);
151 return i != 0 && i != -1;
152}
153
154
155RTDECL(bool) RTMpIsCpuPossible(RTCPUID idCpu)
156{
157 /** @todo check this up with hotplugging! */
158 return RTLinuxSysFsExists("devices/system/cpu/cpu%d", (int)idCpu);
159}
160
161
162RTDECL(PRTCPUSET) RTMpGetSet(PRTCPUSET pSet)
163{
164 RTCpuSetEmpty(pSet);
165 RTCPUID cMax = rtMpLinuxMaxCpus();
166 for (RTCPUID idCpu = 0; idCpu < cMax; idCpu++)
167 if (RTMpIsCpuPossible(idCpu))
168 RTCpuSetAdd(pSet, idCpu);
169 return pSet;
170}
171
172
173RTDECL(RTCPUID) RTMpGetCount(void)
174{
175 RTCPUSET Set;
176 RTMpGetSet(&Set);
177 return RTCpuSetCount(&Set);
178}
179
180
181RTDECL(PRTCPUSET) RTMpGetOnlineSet(PRTCPUSET pSet)
182{
183 RTCpuSetEmpty(pSet);
184 RTCPUID cMax = rtMpLinuxMaxCpus();
185 for (RTCPUID idCpu = 0; idCpu < cMax; idCpu++)
186 if (RTMpIsCpuOnline(idCpu))
187 RTCpuSetAdd(pSet, idCpu);
188 return pSet;
189}
190
191
192RTDECL(RTCPUID) RTMpGetOnlineCount(void)
193{
194 RTCPUSET Set;
195 RTMpGetOnlineSet(&Set);
196 return RTCpuSetCount(&Set);
197}
198
199
200RTDECL(uint32_t) RTMpGetCurFrequency(RTCPUID idCpu)
201{
202 int64_t kHz = RTLinuxSysFsReadIntFile(0, "devices/system/cpu/cpu%d/cpufreq/cpuinfo_cur_freq", (int)idCpu);
203 if (kHz == -1)
204 {
205 /*
206 * The file may be just unreadable - in that case use plan B, i.e.
207 * /proc/cpuinfo to get the data we want. The assumption is that if
208 * cpuinfo_cur_freq doesn't exist then the speed won't change, and
209 * thus cur == max. If it does exist then cpuinfo contains the
210 * current frequency.
211 */
212 kHz = rtMpLinuxGetFrequency(idCpu) * 1000;
213 }
214 return (kHz + 999) / 1000;
215}
216
217
218RTDECL(uint32_t) RTMpGetMaxFrequency(RTCPUID idCpu)
219{
220 int64_t kHz = RTLinuxSysFsReadIntFile(0, "devices/system/cpu/cpu%d/cpufreq/cpuinfo_max_freq", (int)idCpu);
221 if (kHz == -1)
222 {
223 /*
224 * Check if the file isn't there - if it is there, then /proc/cpuinfo
225 * would provide current frequency information, which is wrong.
226 */
227 if (!RTLinuxSysFsExists("devices/system/cpu/cpu%d/cpufreq/cpuinfo_max_freq", (int)idCpu))
228 kHz = rtMpLinuxGetFrequency(idCpu) * 1000;
229 else
230 kHz = 0;
231 }
232 return (kHz + 999) / 1000;
233}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette