Skip to content

Commit 085a58d

Browse files
committed
cache cpu info in a file at boot
Instrumented cpuinfo to read the populated cpu info data from cpuid.info file during initialization. Consumers of the library or OEMs can trigger a oneshot service - cpuinfo-svc - during device boot to link libcpuinfo and dump all cpu info related to processor, model, arch and isa capabilities into cpuid.info file. This arrangement will limit cpuid() intrinsic calls (which causes VM-Exit events and performance overhead) to only once during init of libcpuinfo at boot by cpuinfo-svc. Signed-off-by: Balakrishnan Unnithan <[email protected]>
1 parent f6c059f commit 085a58d

File tree

7 files changed

+322
-2
lines changed

7 files changed

+322
-2
lines changed

deps/clog/include/clog.h

+5-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,11 @@
1212
#define CLOG_DEBUG 5
1313

1414
#ifndef CLOG_VISIBILITY
15-
#if defined(__ELF__)
15+
#if defined(__GNUC__)
16+
// ld.lld: error: undefined hidden symbol: clog_vlog_error
17+
// referenced by log.h:16 (external/cpuinfo/src/cpuinfo/log.h)
18+
#define CLOG_VISIBILITY
19+
#elif defined(__ELF__)
1620
#define CLOG_VISIBILITY __attribute__((__visibility__("internal")))
1721
#elif defined(__MACH__)
1822
#define CLOG_VISIBILITY __attribute__((__visibility__("hidden")))

include/cpuinfo.h

+27
Original file line numberDiff line numberDiff line change
@@ -860,11 +860,38 @@ struct cpuinfo_x86_isa {
860860
bool phe;
861861
bool pmm;
862862
bool lwp;
863+
bool erms;
864+
bool smap;
865+
bool serialize;
863866
};
864867

865868
extern struct cpuinfo_x86_isa cpuinfo_isa;
866869
#endif
867870

871+
static inline bool cpuinfo_has_x86_erms(void) {
872+
#if CPUINFO_ARCH_X86 || CPUINFO_ARCH_X86_64
873+
return cpuinfo_isa.erms;
874+
#else
875+
return false;
876+
#endif
877+
}
878+
879+
static inline bool cpuinfo_has_x86_smap(void) {
880+
#if CPUINFO_ARCH_X86 || CPUINFO_ARCH_X86_64
881+
return cpuinfo_isa.smap;
882+
#else
883+
return false;
884+
#endif
885+
}
886+
887+
static inline bool cpuinfo_has_x86_serialize(void) {
888+
#if CPUINFO_ARCH_X86 || CPUINFO_ARCH_X86_64
889+
return cpuinfo_isa.serialize;
890+
#else
891+
return false;
892+
#endif
893+
}
894+
868895
static inline bool cpuinfo_has_x86_rdtsc(void) {
869896
#if CPUINFO_ARCH_X86_64
870897
return true;

src/x86/init.c

+38-1
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,41 @@
77
#include <cpuinfo/utils.h>
88
#include <x86/api.h>
99
#include <x86/cpuid.h>
10+
#include <x86/linux/api.h>
1011

11-
struct cpuinfo_x86_isa cpuinfo_isa = {0};
12+
/*
13+
* Structs cpuinfo_x86_isa, cpuinfo_x86_model_info and cpuinfo_x86_processor
14+
* are dumped into cpuid.info file by cpuinfo-svc service on boot.
15+
* Whenever libcpuinfo is initialized by any application, it will attempt to
16+
* read cpuid.info file, if it exists, and the binary dump in the file is
17+
* copied to these structs. If the file doesn't exist, we will fall back to
18+
* original method of calling __cpuid() intrinsics to get the info.
19+
* By this method, we can avoid __cpuid() calls during each init of cpuinfo.
20+
* This will reduce VMX events in virtualized environments thereby
21+
* improving performance.
22+
*/
23+
24+
25+
#ifdef __ANDROID__
26+
struct cpuinfo_x86_cpuid_info x86_cpuid_info = { 0 };
27+
#endif // __ANDROID__
28+
29+
struct cpuinfo_x86_isa cpuinfo_isa = { 0 };
1230
CPUINFO_INTERNAL uint32_t cpuinfo_x86_clflush_size = 0;
1331

1432
void cpuinfo_x86_init_processor(struct cpuinfo_x86_processor* processor) {
33+
#ifdef __ANDROID__
34+
if (cpuinfo_x86_linux_parse_cpuid_info(&x86_cpuid_info)) {
35+
*processor = x86_cpuid_info.processor;
36+
cpuinfo_isa = x86_cpuid_info.isa;
37+
#ifdef __DEBUG__
38+
print_cpuid_info_file();
39+
#endif
40+
return;
41+
}
42+
cpuinfo_log_debug("falling back to __cpuid() method");
43+
#endif // __ANDROID__
44+
1545
const struct cpuid_regs leaf0 = cpuid(0);
1646
const uint32_t max_base_index = leaf0.eax;
1747
const enum cpuinfo_vendor vendor = processor->vendor =
@@ -48,6 +78,9 @@ void cpuinfo_x86_init_processor(struct cpuinfo_x86_processor* processor) {
4878

4979
cpuinfo_isa = cpuinfo_x86_detect_isa(
5080
leaf1, leaf0x80000001, max_base_index, max_extended_index, vendor, uarch);
81+
#ifdef __ANDROID__
82+
x86_cpuid_info.model = model_info;
83+
#endif // __ANDROID__
5184
}
5285
if (max_extended_index >= UINT32_C(0x80000004)) {
5386
struct cpuid_regs brand_string[3];
@@ -57,4 +90,8 @@ void cpuinfo_x86_init_processor(struct cpuinfo_x86_processor* processor) {
5790
memcpy(processor->brand_string, brand_string, sizeof(processor->brand_string));
5891
cpuinfo_log_debug("raw CPUID brand string: \"%48s\"", processor->brand_string);
5992
}
93+
#ifdef __ANDROID__
94+
x86_cpuid_info.isa = cpuinfo_isa;
95+
x86_cpuid_info.processor = *processor;
96+
#endif // __ANDROID__
6097
}

src/x86/isa.c

+18
Original file line numberDiff line numberDiff line change
@@ -814,5 +814,23 @@ struct cpuinfo_x86_isa cpuinfo_x86_detect_isa(
814814
*/
815815
isa.rdpid = !!(structured_feature_info0.ecx & UINT32_C(0x00400000));
816816

817+
/*
818+
* ERMS instruction:
819+
* - Intel: ebx[bit 9] in structured feature info (ecx = 0).
820+
*/
821+
isa.erms = !!(structured_feature_info0.ebx & UINT32_C(0x00000200));
822+
823+
/*
824+
* SMAP instruction:
825+
* - Intel: ebx[bit 20] in structured feature info (ecx = 0).
826+
*/
827+
isa.smap = !!(structured_feature_info0.ebx & UINT32_C(0x00100000));
828+
829+
/*
830+
* SERIALIZE instruction:
831+
* - Intel: edx[bit 14] in structured feature info (ecx = 0).
832+
*/
833+
isa.serialize = !!(structured_feature_info0.edx & UINT32_C(0x00004000));
834+
817835
return isa;
818836
}

src/x86/linux/api.h

+17
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,20 @@ struct cpuinfo_x86_linux_processor {
1717
CPUINFO_INTERNAL bool cpuinfo_x86_linux_parse_proc_cpuinfo(
1818
uint32_t max_processors_count,
1919
struct cpuinfo_x86_linux_processor processors[restrict static max_processors_count]);
20+
21+
#ifdef __ANDROID__
22+
#define CPUID_INFO_FILE "/data/system/cpuid.info"
23+
24+
struct cpuinfo_x86_cpuid_info {
25+
struct cpuinfo_x86_isa isa;
26+
struct cpuinfo_x86_model_info model;
27+
struct cpuinfo_x86_processor processor;
28+
};
29+
30+
CPUINFO_INTERNAL bool cpuinfo_x86_linux_parse_cpuid_info(
31+
struct cpuinfo_x86_cpuid_info* x86_cpuid_info);
32+
33+
#ifdef __DEBUG__
34+
CPUINFO_INTERNAL void print_cpuid_info_file(void);
35+
#endif //__DEBUG__
36+
#endif //__ANDROID__

src/x86/linux/cpuinfo.c

+123
Original file line numberDiff line numberDiff line change
@@ -217,3 +217,126 @@ bool cpuinfo_x86_linux_parse_proc_cpuinfo(
217217
return cpuinfo_linux_parse_multiline_file(
218218
"/proc/cpuinfo", BUFFER_SIZE, (cpuinfo_line_callback)parse_line, &state);
219219
}
220+
221+
#ifdef __ANDROID__
222+
bool cpuinfo_x86_linux_parse_cpuid_info(
223+
struct cpuinfo_x86_cpuid_info* x86_cpuid_info)
224+
{
225+
cpuinfo_log_debug("reading cpuid.info file");
226+
FILE* fd_info = fopen(CPUID_INFO_FILE, "rb");
227+
if (!fd_info) {
228+
cpuinfo_log_warning("failed to open file %s: %s", CPUID_INFO_FILE, strerror(errno));
229+
return false;
230+
}
231+
232+
int ret = fread(x86_cpuid_info, sizeof(struct cpuinfo_x86_cpuid_info), 1, fd_info);
233+
if (!ret) {
234+
cpuinfo_log_warning("failed to read cpuid info from %s: %s", CPUID_INFO_FILE, strerror(errno));
235+
}
236+
237+
if (fclose(fd_info)) {
238+
cpuinfo_log_warning("failed to close file %s: %s", CPUID_INFO_FILE, strerror(errno));
239+
}
240+
241+
return ret ? true : false;
242+
}
243+
244+
#ifdef __DEBUG__
245+
void print_cpuid_info_file (void)
246+
{
247+
cpuinfo_log_debug("----------------------------");
248+
/*
249+
cpuinfo_log_debug("%-20s: %d", "ace", cpuinfo_has_x86_ace());
250+
cpuinfo_log_debug("%-20s: %d", "ace2", cpuinfo_has_x86_ace2());
251+
cpuinfo_log_debug("%-20s: %d", "clflush", cpuinfo_has_x86_clflush());
252+
cpuinfo_log_debug("%-20s: %d", "clflushopt", cpuinfo_has_x86_clflushopt());
253+
cpuinfo_log_debug("%-20s: %d", "lwp", cpuinfo_has_x86_lwp());
254+
cpuinfo_log_debug("%-20s: %d", "msr", cpuinfo_has_x86_msr());
255+
cpuinfo_log_debug("%-20s: %d", "phe", cpuinfo_has_x86_phe());
256+
cpuinfo_log_debug("%-20s: %d", "pmm", cpuinfo_has_x86_pmm());
257+
cpuinfo_log_debug("%-20s: %d", "rng", cpuinfo_has_x86_rng());
258+
cpuinfo_log_debug("%-20s: %d", "sysenter", cpuinfo_has_x86_sysenter());
259+
cpuinfo_log_debug("%-20s: %d", "syscall", cpuinfo_has_x86_syscall());
260+
cpuinfo_log_debug("%-20s: %d", "emmx", cpuinfo_has_x86_emmx());
261+
cpuinfo_log_debug("%-20s: %d", "fs_gs_base", cpuinfo_has_x86_fs_gs_base());
262+
cpuinfo_log_debug("%-20s: %d", "fxsave", cpuinfo_has_x86_fxsave());
263+
*/
264+
cpuinfo_log_debug("%-20s: %d", "erms", cpuinfo_has_x86_erms());
265+
cpuinfo_log_debug("%-20s: %d", "smap", cpuinfo_has_x86_smap());
266+
cpuinfo_log_debug("%-20s: %d", "serialize", cpuinfo_has_x86_serialize());
267+
cpuinfo_log_debug("%-20s: %d", "adx", cpuinfo_has_x86_adx());
268+
cpuinfo_log_debug("%-20s: %d", "aes", cpuinfo_has_x86_aes());
269+
cpuinfo_log_debug("%-20s: %d", "avx", cpuinfo_has_x86_avx());
270+
cpuinfo_log_debug("%-20s: %d", "avx2", cpuinfo_has_x86_avx2());
271+
cpuinfo_log_debug("%-20s: %d", "avx512bf16", cpuinfo_has_x86_avx512bf16());
272+
cpuinfo_log_debug("%-20s: %d", "avx512bitalg", cpuinfo_has_x86_avx512bitalg());
273+
cpuinfo_log_debug("%-20s: %d", "avx512bw", cpuinfo_has_x86_avx512bw());
274+
cpuinfo_log_debug("%-20s: %d", "avx512cd", cpuinfo_has_x86_avx512cd());
275+
cpuinfo_log_debug("%-20s: %d", "avx512dq", cpuinfo_has_x86_avx512dq());
276+
cpuinfo_log_debug("%-20s: %d", "avx512er", cpuinfo_has_x86_avx512er());
277+
cpuinfo_log_debug("%-20s: %d", "avx512f", cpuinfo_has_x86_avx512f());
278+
cpuinfo_log_debug("%-20s: %d", "avx512ifma", cpuinfo_has_x86_avx512ifma());
279+
cpuinfo_log_debug("%-20s: %d", "avx512pf", cpuinfo_has_x86_avx512pf());
280+
cpuinfo_log_debug("%-20s: %d", "avx512vbmi", cpuinfo_has_x86_avx512vbmi());
281+
cpuinfo_log_debug("%-20s: %d", "avx512vbmi2", cpuinfo_has_x86_avx512vbmi2());
282+
cpuinfo_log_debug("%-20s: %d", "avx512vl", cpuinfo_has_x86_avx512vl());
283+
cpuinfo_log_debug("%-20s: %d", "avx512vnni", cpuinfo_has_x86_avx512vnni());
284+
cpuinfo_log_debug("%-20s: %d", "avx512vp2intersect", cpuinfo_has_x86_avx512vp2intersect());
285+
cpuinfo_log_debug("%-20s: %d", "avx512vpopcntdq", cpuinfo_has_x86_avx512vpopcntdq());
286+
cpuinfo_log_debug("%-20s: %d", "avx512_4fmaps", cpuinfo_has_x86_avx512_4fmaps());
287+
cpuinfo_log_debug("%-20s: %d", "avx512_4vnniw", cpuinfo_has_x86_avx512_4vnniw());
288+
cpuinfo_log_debug("%-20s: %d", "bmi", cpuinfo_has_x86_bmi());
289+
cpuinfo_log_debug("%-20s: %d", "bmi2", cpuinfo_has_x86_bmi2());
290+
cpuinfo_log_debug("%-20s: %d", "clwb", cpuinfo_has_x86_clwb());
291+
cpuinfo_log_debug("%-20s: %d", "clzero", cpuinfo_has_x86_clzero());
292+
cpuinfo_log_debug("%-20s: %d", "cmpxchg16b", cpuinfo_has_x86_cmpxchg16b());
293+
cpuinfo_log_debug("%-20s: %d", "f16c", cpuinfo_has_x86_f16c());
294+
cpuinfo_log_debug("%-20s: %d", "fma3", cpuinfo_has_x86_fma3());
295+
cpuinfo_log_debug("%-20s: %d", "fma4", cpuinfo_has_x86_fma4());
296+
cpuinfo_log_debug("%-20s: %d", "gfni", cpuinfo_has_x86_gfni());
297+
cpuinfo_log_debug("%-20s: %d", "hle", cpuinfo_has_x86_hle());
298+
cpuinfo_log_debug("%-20s: %d", "lzcnt", cpuinfo_has_x86_lzcnt());
299+
cpuinfo_log_debug("%-20s: %d", "misaligned_sse", cpuinfo_has_x86_misaligned_sse());
300+
cpuinfo_log_debug("%-20s: %d", "movbe", cpuinfo_has_x86_movbe());
301+
cpuinfo_log_debug("%-20s: %d", "mpx", cpuinfo_has_x86_mpx());
302+
cpuinfo_log_debug("%-20s: %d", "mwait", cpuinfo_has_x86_mwait());
303+
cpuinfo_log_debug("%-20s: %d", "mwaitx", cpuinfo_has_x86_mwaitx());
304+
cpuinfo_log_debug("%-20s: %d", "pclmulqdq", cpuinfo_has_x86_pclmulqdq());
305+
cpuinfo_log_debug("%-20s: %d", "popcnt", cpuinfo_has_x86_popcnt());
306+
cpuinfo_log_debug("%-20s: %d", "prefetch", cpuinfo_has_x86_prefetch());
307+
cpuinfo_log_debug("%-20s: %d", "prefetchw", cpuinfo_has_x86_prefetchw());
308+
cpuinfo_log_debug("%-20s: %d", "prefetchwt1", cpuinfo_has_x86_prefetchwt1());
309+
cpuinfo_log_debug("%-20s: %d", "rdpid", cpuinfo_has_x86_rdpid());
310+
cpuinfo_log_debug("%-20s: %d", "rdrand", cpuinfo_has_x86_rdrand());
311+
cpuinfo_log_debug("%-20s: %d", "rdseed", cpuinfo_has_x86_rdseed());
312+
cpuinfo_log_debug("%-20s: %d", "rdtscp", cpuinfo_has_x86_rdtscp());
313+
cpuinfo_log_debug("%-20s: %d", "rtm", cpuinfo_has_x86_rtm());
314+
cpuinfo_log_debug("%-20s: %d", "sha", cpuinfo_has_x86_sha());
315+
cpuinfo_log_debug("%-20s: %d", "sse3", cpuinfo_has_x86_sse3());
316+
cpuinfo_log_debug("%-20s: %d", "sse4a", cpuinfo_has_x86_sse4a());
317+
cpuinfo_log_debug("%-20s: %d", "sse4_1", cpuinfo_has_x86_sse4_1());
318+
cpuinfo_log_debug("%-20s: %d", "sse4_2", cpuinfo_has_x86_sse4_2());
319+
cpuinfo_log_debug("%-20s: %d", "ssse3", cpuinfo_has_x86_ssse3());
320+
cpuinfo_log_debug("%-20s: %d", "tbm", cpuinfo_has_x86_tbm());
321+
cpuinfo_log_debug("%-20s: %d", "three_d_now", cpuinfo_has_x86_3dnow());
322+
cpuinfo_log_debug("%-20s: %d", "three_d_now_plus", cpuinfo_has_x86_3dnow_plus());
323+
cpuinfo_log_debug("%-20s: %d", "vaes", cpuinfo_has_x86_vaes());
324+
cpuinfo_log_debug("%-20s: %d", "vpclmulqdq", cpuinfo_has_x86_vpclmulqdq());
325+
cpuinfo_log_debug("%-20s: %d", "xop", cpuinfo_has_x86_xop());
326+
cpuinfo_log_debug("%-20s: %d", "xsave", cpuinfo_has_x86_xsave());
327+
cpuinfo_log_debug("%-20s: %d", "xtest", cpuinfo_has_x86_xtest());
328+
cpuinfo_log_debug("%-20s: %d", "cmov", cpuinfo_has_x86_cmov());
329+
cpuinfo_log_debug("%-20s: %d", "cmpxchg8b", cpuinfo_has_x86_cmpxchg8b());
330+
cpuinfo_log_debug("%-20s: %d", "daz", cpuinfo_has_x86_daz());
331+
cpuinfo_log_debug("%-20s: %d", "fpu", cpuinfo_has_x86_fpu());
332+
cpuinfo_log_debug("%-20s: %d", "mmx", cpuinfo_has_x86_mmx());
333+
cpuinfo_log_debug("%-20s: %d", "mmx_plus", cpuinfo_has_x86_mmx_plus());
334+
cpuinfo_log_debug("%-20s: %d", "rdtsc", cpuinfo_has_x86_rdtsc());
335+
cpuinfo_log_debug("%-20s: %d", "sse", cpuinfo_has_x86_sse());
336+
cpuinfo_log_debug("%-20s: %d", "sse2", cpuinfo_has_x86_sse2());
337+
cpuinfo_log_debug("%-20s: %d", "three_d_now_geode", cpuinfo_has_x86_3dnow_geode());
338+
cpuinfo_log_debug("%-20s: %d", "lahf_sahf", cpuinfo_has_x86_lahf_sahf());
339+
cpuinfo_log_debug("----------------------------");
340+
}
341+
#endif // __DEBUG__
342+
#endif // __ANDROID__

tools/cpuinfo-svc.c

+94
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
/* Copyright (C) 2024 Intel Corporation
2+
* All rights reserved.
3+
*
4+
* Redistribution and use in source and binary forms, with or without modification,
5+
* are permitted provided that the following conditions are met:
6+
*
7+
* 1. Redistributions of source code must retain the above copyright notice,
8+
*    this list of conditions and the following disclaimer.
9+
* 2. Redistributions in binary form must reproduce the above copyright notice,
10+
*    this list of conditions and the following disclaimer in the documentation
11+
*    and/or other materials provided with the distribution.
12+
* 3. Neither the name of the copyright holder nor the names of its contributors
13+
*    may be used to endorse or promote products derived from this software
14+
*    without specific prior written permission.
15+
*
16+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
18+
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19+
* ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
20+
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
21+
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
22+
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
23+
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24+
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25+
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
26+
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27+
*
28+
* SPDX-License-Identifier: BSD-3-Clause
29+
*/
30+
31+
/*
32+
* Description: cpuinfo-service to initialize and dump cpu info collected
33+
* through __cpuid() calls during device boot.
34+
* it will delete cpuid.info file if it exits and create new.
35+
*
36+
* Author: Unnithan, Balakrishnan <[email protected]>
37+
*/
38+
39+
40+
#include <stdbool.h>
41+
#include <stdlib.h>
42+
#include <string.h>
43+
#include <errno.h>
44+
45+
#include <cpuinfo.h>
46+
#include <cpuinfo/common.h>
47+
#include <cpuinfo/log.h>
48+
#include <x86/linux/api.h>
49+
50+
#ifdef __ANDROID__
51+
extern struct cpuinfo_x86_cpuid_info x86_cpuid_info;
52+
53+
CPUINFO_INTERNAL bool write_cpuid_info_file (void) {
54+
cpuinfo_log_debug("writing cpuid.info file");
55+
FILE* fd_info = fopen(CPUID_INFO_FILE, "wb");
56+
if (!fd_info) {
57+
cpuinfo_log_error("failed to open file %s: %s", CPUID_INFO_FILE, strerror(errno));
58+
return false;
59+
}
60+
61+
int ret = fwrite(&x86_cpuid_info, sizeof(struct cpuinfo_x86_cpuid_info), 1, fd_info);
62+
if (!ret) {
63+
cpuinfo_log_error("failed to write cpuid info in %s: %s", CPUID_INFO_FILE, strerror(errno));
64+
}
65+
66+
if (fclose(fd_info)) {
67+
cpuinfo_log_error("failed to close file %s: %s", CPUID_INFO_FILE, strerror(errno));
68+
return false;
69+
}
70+
71+
return ret ? true : false;
72+
}
73+
#endif // __ANDROID__
74+
75+
int main (void) {
76+
cpuinfo_log_info("start service");
77+
#ifdef __ANDROID__
78+
if (remove(CPUID_INFO_FILE)) {
79+
cpuinfo_log_warning("failed to delete file %s: %s", CPUID_INFO_FILE, strerror(errno));
80+
}
81+
82+
if (!cpuinfo_initialize()) {
83+
cpuinfo_log_error("failed to init cpuinfo lib. exit");
84+
return 1;
85+
}
86+
87+
if (!write_cpuid_info_file()) {
88+
cpuinfo_log_error("failed to save cpuid info. exit");
89+
return 1;
90+
}
91+
#endif // __ANDROID__
92+
cpuinfo_log_info("exit service");
93+
return 0;
94+
}

0 commit comments

Comments
 (0)