diff options
Diffstat (limited to 'src/VBox/Runtime/r3/solaris/mp-solaris.cpp')
-rw-r--r-- | src/VBox/Runtime/r3/solaris/mp-solaris.cpp | 182 |
1 files changed, 164 insertions, 18 deletions
diff --git a/src/VBox/Runtime/r3/solaris/mp-solaris.cpp b/src/VBox/Runtime/r3/solaris/mp-solaris.cpp index 0f2c6fdf..d21bbb42 100644 --- a/src/VBox/Runtime/r3/solaris/mp-solaris.cpp +++ b/src/VBox/Runtime/r3/solaris/mp-solaris.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2008 Oracle Corporation + * Copyright (C) 2008-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -57,19 +57,77 @@ static kstat_ctl_t *g_pKsCtl; static kstat_t **g_papCpuInfo; /** The number of entries in g_papCpuInfo */ static RTCPUID g_capCpuInfo; +/** Array of core ids. */ +static uint64_t *g_pu64CoreIds; +/** Number of entries in g_pu64CoreIds. */ +static size_t g_cu64CoreIds; +/** Number of cores in the system. */ +static size_t g_cCores; + + +/** + * Helper for getting the core ID for a given CPU/strand/hyperthread. + * + * @returns The core ID. + * @param idCpu The CPU ID instance. + */ +static inline uint64_t rtMpSolarisGetCoreId(RTCPUID idCpu) +{ + kstat_named_t *pStat = (kstat_named_t *)kstat_data_lookup(g_papCpuInfo[idCpu], (char *)"core_id"); + Assert(pStat->data_type == KSTAT_DATA_LONG); + Assert(pStat->value.l >= 0); + AssertCompile(sizeof(uint64_t) >= sizeof(long)); /* Paranoia. */ + return (uint64_t)pStat->value.l; +} + + +/** + * Populates 'g_pu64CoreIds' array with unique core identifiers in the system. + * + * @returns VBox status code. + */ +static int rtMpSolarisGetCoreIds(void) +{ + for (RTCPUID idCpu = 0; idCpu < g_capCpuInfo; idCpu++) + { + if (kstat_read(g_pKsCtl, g_papCpuInfo[idCpu], 0) != -1) + { + /* Strands/Hyperthreads share the same core ID. */ + uint64_t u64CoreId = rtMpSolarisGetCoreId(idCpu); + bool fAddedCore = false; + for (RTCPUID i = 0; i < g_cCores; i++) + { + if (g_pu64CoreIds[i] == u64CoreId) + { + fAddedCore = true; + break; + } + } + + if (!fAddedCore) + { + g_pu64CoreIds[g_cCores] = u64CoreId; + ++g_cCores; + } + } + else + return VERR_INTERNAL_ERROR_2; + } + + return VINF_SUCCESS; +} /** * Run once function that initializes the kstats we need here. * * @returns IPRT status code. - * @param pvUser1 Unused. - * @param pvUser2 Unused. + * @param pvUser Unused. */ -static DECLCALLBACK(int) rtMpSolarisOnce(void *pvUser1, void *pvUser2) +static DECLCALLBACK(int) rtMpSolarisOnce(void *pvUser) { int rc = VINF_SUCCESS; - NOREF(pvUser1); NOREF(pvUser2); + NOREF(pvUser); /* * Open kstat and find the cpu_info entries for each of the CPUs. @@ -81,25 +139,40 @@ static DECLCALLBACK(int) rtMpSolarisOnce(void *pvUser1, void *pvUser2) g_papCpuInfo = (kstat_t **)RTMemAllocZ(g_capCpuInfo * sizeof(kstat_t *)); if (g_papCpuInfo) { - rc = RTCritSectInit(&g_MpSolarisCritSect); - if (RT_SUCCESS(rc)) + g_cu64CoreIds = g_capCpuInfo; + g_pu64CoreIds = (uint64_t *)RTMemAllocZ(g_cu64CoreIds * sizeof(uint64_t)); + if (g_pu64CoreIds) { - RTCPUID i = 0; - for (kstat_t *pKsp = g_pKsCtl->kc_chain; pKsp != NULL; pKsp = pKsp->ks_next) + rc = RTCritSectInit(&g_MpSolarisCritSect); + if (RT_SUCCESS(rc)) { - if (!strcmp(pKsp->ks_module, "cpu_info")) + RTCPUID i = 0; + for (kstat_t *pKsp = g_pKsCtl->kc_chain; pKsp != NULL; pKsp = pKsp->ks_next) { - AssertBreak(i < g_capCpuInfo); - g_papCpuInfo[i++] = pKsp; - /** @todo ks_instance == cpu_id (/usr/src/uts/common/os/cpu.c)? Check this and fix it ASAP. */ + if (!RTStrCmp(pKsp->ks_module, "cpu_info")) + { + AssertBreak(i < g_capCpuInfo); + g_papCpuInfo[i++] = pKsp; + /** @todo ks_instance == cpu_id (/usr/src/uts/common/os/cpu.c)? Check this and fix it ASAP. */ + } } + + rc = rtMpSolarisGetCoreIds(); + if (RT_SUCCESS(rc)) + return VINF_SUCCESS; + else + Log(("rtMpSolarisGetCoreIds failed. rc=%Rrc\n", rc)); } - return VINF_SUCCESS; + RTMemFree(g_pu64CoreIds); + g_pu64CoreIds = NULL; } + else + rc = VERR_NO_MEMORY; /* bail out, we failed. */ RTMemFree(g_papCpuInfo); + g_papCpuInfo = NULL; } else rc = VERR_NO_MEMORY; @@ -119,6 +192,21 @@ static DECLCALLBACK(int) rtMpSolarisOnce(void *pvUser1, void *pvUser2) /** + * RTOnceEx() cleanup function. + * + * @param pvUser Unused. + * @param fLazyCleanUpOk Whether lazy cleanup is okay or not. + */ +static DECLCALLBACK(void) rtMpSolarisCleanUp(void *pvUser, bool fLazyCleanUpOk) +{ + if (g_pKsCtl) + kstat_close(g_pKsCtl); + RTMemFree(g_pu64CoreIds); + RTMemFree(g_papCpuInfo); +} + + +/** * Worker for RTMpGetCurFrequency and RTMpGetMaxFrequency. * * @returns The desired frequency on success, 0 on failure. @@ -126,10 +214,10 @@ static DECLCALLBACK(int) rtMpSolarisOnce(void *pvUser1, void *pvUser2) * @param idCpu The CPU ID. * @param pszStatName The cpu_info stat name. */ -static uint64_t rtMpSolarisGetFrequency(RTCPUID idCpu, char *pszStatName) +static uint64_t rtMpSolarisGetFrequency(RTCPUID idCpu, const char *pszStatName) { uint64_t u64 = 0; - int rc = RTOnce(&g_MpSolarisOnce, rtMpSolarisOnce, NULL, NULL); + int rc = RTOnceEx(&g_MpSolarisOnce, rtMpSolarisOnce, rtMpSolarisCleanUp, NULL /* pvUser */); if (RT_SUCCESS(rc)) { if ( idCpu < g_capCpuInfo @@ -141,7 +229,8 @@ static uint64_t rtMpSolarisGetFrequency(RTCPUID idCpu, char *pszStatName) { if (kstat_read(g_pKsCtl, g_papCpuInfo[idCpu], 0) != -1) { - kstat_named_t *pStat = (kstat_named_t *)kstat_data_lookup(g_papCpuInfo[idCpu], pszStatName); + /* Solaris really need to fix their APIs. Explicitly cast for now. */ + kstat_named_t *pStat = (kstat_named_t *)kstat_data_lookup(g_papCpuInfo[idCpu], (char*)pszStatName); if (pStat) { Assert(pStat->data_type == KSTAT_DATA_UINT64 || pStat->data_type == KSTAT_DATA_LONG); @@ -280,7 +369,7 @@ RTDECL(PRTCPUSET) RTMpGetOnlineSet(PRTCPUSET pSet) RTDECL(PRTCPUSET) RTMpGetPresentSet(PRTCPUSET pSet) { #ifdef RT_STRICT - long cCpusPresent = 0; + RTCPUID cCpusPresent = 0; #endif RTCpuSetEmpty(pSet); RTCPUID cCpus = RTMpGetCount(); @@ -305,3 +394,60 @@ RTDECL(RTCPUID) RTMpGetPresentCount(void) return sysconf(_SC_NPROCESSORS_CONF); } + +RTDECL(RTCPUID) RTMpGetPresentCoreCount(void) +{ + return RTMpGetCoreCount(); +} + + +RTDECL(RTCPUID) RTMpGetCoreCount(void) +{ + int rc = RTOnceEx(&g_MpSolarisOnce, rtMpSolarisOnce, rtMpSolarisCleanUp, NULL /* pvUser */); + if (RT_SUCCESS(rc)) + return g_cCores; + + return 0; +} + + +RTDECL(RTCPUID) RTMpGetOnlineCoreCount(void) +{ + RTCPUID uOnlineCores = 0; + int rc = RTOnceEx(&g_MpSolarisOnce, rtMpSolarisOnce, rtMpSolarisCleanUp, NULL /* pvUser */); + if (RT_SUCCESS(rc)) + { + rc = RTCritSectEnter(&g_MpSolarisCritSect); + AssertRC(rc); + + /* + * For each core in the system, count how many are currently online. + */ + for (RTCPUID j = 0; j < g_cCores; j++) + { + uint64_t u64CoreId = g_pu64CoreIds[j]; + for (RTCPUID idCpu = 0; idCpu < g_capCpuInfo; idCpu++) + { + rc = kstat_read(g_pKsCtl, g_papCpuInfo[idCpu], 0); + AssertReturn(rc != -1, 0 /* rc */); + uint64_t u64ThreadCoreId = rtMpSolarisGetCoreId(idCpu); + if (u64ThreadCoreId == u64CoreId) + { + kstat_named_t *pStat = (kstat_named_t *)kstat_data_lookup(g_papCpuInfo[idCpu], (char *)"state"); + Assert(pStat->data_type == KSTAT_DATA_CHAR); + if( !RTStrNCmp(pStat->value.c, PS_ONLINE, sizeof(PS_ONLINE) - 1) + || !RTStrNCmp(pStat->value.c, PS_NOINTR, sizeof(PS_NOINTR) - 1)) + { + uOnlineCores++; + break; /* Move to the next core. We have at least 1 hyperthread online in the current core. */ + } + } + } + } + + RTCritSectLeave(&g_MpSolarisCritSect); + } + + return uOnlineCores; +} + |