/src/tdengine/source/os/src/osSysinfo.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com> |
3 | | * |
4 | | * This program is free software: you can use, redistribute, and/or modify |
5 | | * it under the terms of the GNU Affero General Public License, version 3 |
6 | | * or later ("AGPL"), as published by the Free Software Foundation. |
7 | | * |
8 | | * This program is distributed in the hope that it will be useful, but WITHOUT |
9 | | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
10 | | * FITNESS FOR A PARTICULAR PURPOSE. |
11 | | * |
12 | | * You should have received a copy of the GNU Affero General Public License |
13 | | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
14 | | */ |
15 | | |
16 | | #define _DEFAULT_SOURCE |
17 | | #include "os.h" |
18 | | #include "taoserror.h" |
19 | | #include "cus_name.h" |
20 | | |
21 | 0 | #define PROCESS_ITEM 12 |
22 | | #define UUIDLEN37 37 |
23 | | |
24 | | typedef struct { |
25 | | uint64_t user; |
26 | | uint64_t nice; |
27 | | uint64_t system; |
28 | | uint64_t idle; |
29 | | uint64_t wa; |
30 | | uint64_t hi; |
31 | | uint64_t si; |
32 | | uint64_t st; |
33 | | uint64_t guest; |
34 | | uint64_t guest_nice; |
35 | | } SysCpuInfo; |
36 | | |
37 | | typedef struct { |
38 | | uint64_t utime; // user time |
39 | | uint64_t stime; // kernel time |
40 | | uint64_t cutime; // all user time |
41 | | uint64_t cstime; // all dead time |
42 | | } ProcCpuInfo; |
43 | | |
44 | | #ifdef WINDOWS |
45 | | |
46 | | /* |
47 | | * windows implementation |
48 | | */ |
49 | | |
50 | | #if (_WIN64) |
51 | | #include <iphlpapi.h> |
52 | | #include <mswsock.h> |
53 | | #include <psapi.h> |
54 | | #include <stdio.h> |
55 | | #include <windows.h> |
56 | | #include <ws2tcpip.h> |
57 | | #pragma comment(lib, "Mswsock.lib ") |
58 | | #endif |
59 | | |
60 | | #include <objbase.h> |
61 | | #include <signal.h> |
62 | | #include <stdlib.h> |
63 | | |
64 | | #pragma warning(push) |
65 | | #pragma warning(disable : 4091) |
66 | | #include <DbgHelp.h> |
67 | | #pragma warning(pop) |
68 | | |
69 | | // Write a single stack frame line to hFile. |
70 | | // dbghelp functions are available via the statically-linked dbghelp.lib. |
71 | | static void taosWinWriteOneFrame(HANDLE hFile, HANDLE hProcess, DWORD64 pc, DWORD idx) { |
72 | | char symBuf[sizeof(SYMBOL_INFO) + MAX_SYM_NAME]; |
73 | | PSYMBOL_INFO pSym = (PSYMBOL_INFO)symBuf; |
74 | | pSym->SizeOfStruct = sizeof(SYMBOL_INFO); |
75 | | pSym->MaxNameLen = MAX_SYM_NAME; |
76 | | |
77 | | DWORD64 symDisp = 0; |
78 | | char *symName = (char *)"<unknown>"; |
79 | | if (SymFromAddr(hProcess, pc, &symDisp, pSym)) { |
80 | | symName = pSym->Name; |
81 | | } |
82 | | |
83 | | IMAGEHLP_LINE64 li = {0}; |
84 | | li.SizeOfStruct = sizeof(IMAGEHLP_LINE64); |
85 | | DWORD lineDisp = 0; |
86 | | |
87 | | char line[4096]; |
88 | | int n; |
89 | | if (SymGetLineFromAddr64(hProcess, pc, &lineDisp, &li)) { |
90 | | n = _snprintf_s(line, sizeof(line), _TRUNCATE, "#%-3lu 0x%016I64X %s (%s:%lu)\r\n", |
91 | | (unsigned long)idx, pc, symName, li.FileName, (unsigned long)li.LineNumber); |
92 | | } else { |
93 | | n = _snprintf_s(line, sizeof(line), _TRUNCATE, "#%-3lu 0x%016I64X %s\r\n", |
94 | | (unsigned long)idx, pc, symName); |
95 | | } |
96 | | DWORD w = 0; |
97 | | if (n > 0) (void)WriteFile(hFile, line, (DWORD)n, &w, NULL); |
98 | | } |
99 | | |
100 | | // Walk the call stack from the exception context and write each frame to hFile. |
101 | | static void taosWinWriteStackTrace(HANDLE hFile, PEXCEPTION_POINTERS ep) { |
102 | | HANDLE hProcess = GetCurrentProcess(); |
103 | | HANDLE hThread = GetCurrentThread(); |
104 | | CONTEXT ctx = *ep->ContextRecord; /* copy: StackWalk64 modifies it */ |
105 | | |
106 | | SymSetOptions(SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS | SYMOPT_LOAD_LINES); |
107 | | SymInitialize(hProcess, NULL, TRUE); |
108 | | |
109 | | STACKFRAME64 sf = {0}; |
110 | | DWORD mach; |
111 | | #if defined(_M_X64) |
112 | | mach = IMAGE_FILE_MACHINE_AMD64; |
113 | | sf.AddrPC.Offset = ctx.Rip; sf.AddrPC.Mode = AddrModeFlat; |
114 | | sf.AddrFrame.Offset = ctx.Rbp; sf.AddrFrame.Mode = AddrModeFlat; |
115 | | sf.AddrStack.Offset = ctx.Rsp; sf.AddrStack.Mode = AddrModeFlat; |
116 | | #elif defined(_M_IX86) |
117 | | mach = IMAGE_FILE_MACHINE_I386; |
118 | | sf.AddrPC.Offset = ctx.Eip; sf.AddrPC.Mode = AddrModeFlat; |
119 | | sf.AddrFrame.Offset = ctx.Ebp; sf.AddrFrame.Mode = AddrModeFlat; |
120 | | sf.AddrStack.Offset = ctx.Esp; sf.AddrStack.Mode = AddrModeFlat; |
121 | | #elif defined(_M_ARM64) |
122 | | mach = IMAGE_FILE_MACHINE_ARM64; |
123 | | sf.AddrPC.Offset = ctx.Pc; sf.AddrPC.Mode = AddrModeFlat; |
124 | | sf.AddrFrame.Offset = ctx.Fp; sf.AddrFrame.Mode = AddrModeFlat; |
125 | | sf.AddrStack.Offset = ctx.Sp; sf.AddrStack.Mode = AddrModeFlat; |
126 | | #else |
127 | | SymCleanup(hProcess); |
128 | | return; /* unsupported architecture */ |
129 | | #endif |
130 | | |
131 | | static const char hdr[] = "=== Stack Trace ===\r\n"; |
132 | | DWORD w = 0; |
133 | | (void)WriteFile(hFile, hdr, (DWORD)(sizeof(hdr) - 1), &w, NULL); |
134 | | |
135 | | for (DWORD i = 0; i < 128; i++) { |
136 | | if (!StackWalk64(mach, hProcess, hThread, &sf, (PVOID)&ctx, |
137 | | NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL)) |
138 | | break; |
139 | | if (sf.AddrPC.Offset == 0) break; |
140 | | taosWinWriteOneFrame(hFile, hProcess, sf.AddrPC.Offset, i); |
141 | | } |
142 | | SymCleanup(hProcess); |
143 | | } |
144 | | |
145 | | LONG WINAPI FlCrashDump(PEXCEPTION_POINTERS ep) { |
146 | | // Only handle fatal exceptions, let others pass through for vectored handler |
147 | | DWORD code = ep->ExceptionRecord->ExceptionCode; |
148 | | |
149 | | // Skip non-fatal exceptions (like breakpoints during debugging) |
150 | | if (code == EXCEPTION_BREAKPOINT || code == EXCEPTION_SINGLE_STEP) { |
151 | | return EXCEPTION_CONTINUE_SEARCH; |
152 | | } |
153 | | |
154 | | typedef BOOL(WINAPI * FxMiniDumpWriteDump)(IN HANDLE hProcess, IN DWORD ProcessId, IN HANDLE hFile, |
155 | | IN MINIDUMP_TYPE DumpType, |
156 | | IN CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, |
157 | | IN CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, |
158 | | IN CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam); |
159 | | |
160 | | // ── 1. load dbghelp ────────────────────────────────────────────────────── |
161 | | HMODULE dll = LoadLibraryA("dbghelp.dll"); |
162 | | if (dll == NULL) return EXCEPTION_CONTINUE_SEARCH; |
163 | | FxMiniDumpWriteDump mdwd = (FxMiniDumpWriteDump)(GetProcAddress(dll, "MiniDumpWriteDump")); |
164 | | if (mdwd == NULL) { |
165 | | FreeLibrary(dll); |
166 | | return EXCEPTION_CONTINUE_SEARCH; |
167 | | } |
168 | | |
169 | | // ── 2. build timestamped file paths next to the running executable ─────── |
170 | | // Keeping dumps beside the exe makes them easy to find. |
171 | | SYSTEMTIME st; |
172 | | GetLocalTime(&st); |
173 | | |
174 | | TdWchar exePath[MAX_PATH]; |
175 | | DWORD exeLen = GetModuleFileNameW(NULL, exePath, MAX_PATH); |
176 | | /* strip the executable filename, keep the trailing backslash */ |
177 | | while (exeLen > 0 && exePath[exeLen - 1] != L'\\') exeLen--; |
178 | | exePath[exeLen] = L'\0'; /* exePath is now the directory with trailing '\' */ |
179 | | |
180 | | TdWchar dmpPath[MAX_PATH]; |
181 | | TdWchar logPath[MAX_PATH]; |
182 | | _snwprintf_s(dmpPath, MAX_PATH, _TRUNCATE, |
183 | | L"%staosd_%04d%02d%02d_%02d%02d%02d.dmp", |
184 | | exePath, st.wYear, st.wMonth, st.wDay, |
185 | | st.wHour, st.wMinute, st.wSecond); |
186 | | _snwprintf_s(logPath, MAX_PATH, _TRUNCATE, |
187 | | L"%staosd_%04d%02d%02d_%02d%02d%02d_stack.log", |
188 | | exePath, st.wYear, st.wMonth, st.wDay, |
189 | | st.wHour, st.wMinute, st.wSecond); |
190 | | |
191 | | // ── 3. write MiniDump with comprehensive type ───────────────────────────── |
192 | | HANDLE dmpFile = CreateFileW(dmpPath, GENERIC_WRITE, 0, NULL, |
193 | | CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); |
194 | | if (dmpFile != INVALID_HANDLE_VALUE) { |
195 | | MINIDUMP_EXCEPTION_INFORMATION mei; |
196 | | mei.ThreadId = GetCurrentThreadId(); |
197 | | mei.ExceptionPointers = ep; |
198 | | mei.ClientPointers = FALSE; |
199 | | |
200 | | MINIDUMP_TYPE dumpType = (MINIDUMP_TYPE)( |
201 | | MiniDumpWithDataSegs | /* global/static variables */ |
202 | | MiniDumpWithProcessThreadData | /* all thread stacks + locals */ |
203 | | MiniDumpWithHandleData | /* open handles */ |
204 | | MiniDumpWithIndirectlyReferencedMemory | /* memory pointed-to by locals */ |
205 | | MiniDumpWithThreadInfo | /* thread times, start addr */ |
206 | | MiniDumpWithFullMemoryInfo); /* all VMAs (flags/state) */ |
207 | | // Keep process/thread data and indirectly referenced memory enabled |
208 | | // to capture more complete diagnostic information in the minidump |
209 | | |
210 | | (*mdwd)(GetCurrentProcess(), GetCurrentProcessId(), dmpFile, |
211 | | dumpType, &mei, NULL, NULL); |
212 | | CloseHandle(dmpFile); |
213 | | } |
214 | | |
215 | | // ── 4. write stack trace text log (usable without PDB on developer side) ── |
216 | | HANDLE logFile = CreateFileW(logPath, GENERIC_WRITE, 0, NULL, |
217 | | CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); |
218 | | if (logFile != INVALID_HANDLE_VALUE) { |
219 | | char hdr[512]; |
220 | | DWORD w = 0; |
221 | | int n = _snprintf_s(hdr, sizeof(hdr), _TRUNCATE, |
222 | | "ExceptionCode: 0x%08lX\r\n" |
223 | | "ExceptionAddress: 0x%016I64X\r\n" |
224 | | "ThreadId: %lu\r\n" |
225 | | "\r\n", |
226 | | ep->ExceptionRecord->ExceptionCode, |
227 | | (DWORD64)(ULONG_PTR)ep->ExceptionRecord->ExceptionAddress, |
228 | | (unsigned long)GetCurrentThreadId()); |
229 | | if (n > 0) (void)WriteFile(logFile, hdr, (DWORD)n, &w, NULL); |
230 | | taosWinWriteStackTrace(logFile, ep); |
231 | | CloseHandle(logFile); |
232 | | } |
233 | | |
234 | | FreeLibrary(dll); |
235 | | |
236 | | // Return EXCEPTION_CONTINUE_SEARCH so that Windows Error Reporting (WER / |
237 | | // WerFault.exe) can write an out-of-process dump as a fallback. WerFault |
238 | | // runs in a separate process and is therefore immune to stack/heap corruption |
239 | | // in this process — it will still produce a valid dump even when |
240 | | // MiniDumpWriteDump above failed (e.g. due to stack overflow or heap |
241 | | // corruption that zeroed out our stack frame). |
242 | | // Configure the WER dump directory via: |
243 | | // HKLM\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps\taosd.exe |
244 | | // DumpFolder REG_EXPAND_SZ <path> |
245 | | // DumpType REG_DWORD 2 (full user-mode dump) |
246 | | // DumpCount REG_DWORD 10 |
247 | | return EXCEPTION_CONTINUE_SEARCH; |
248 | | } |
249 | | |
250 | | // Vectored Exception Handler - called BEFORE SEH, can catch heap corruption |
251 | | static LONG WINAPI FlVectoredExceptionHandler(PEXCEPTION_POINTERS ep) { |
252 | | DWORD code = ep->ExceptionRecord->ExceptionCode; |
253 | | |
254 | | // Only handle critical exceptions that would terminate the process |
255 | | // These exceptions may bypass SetUnhandledExceptionFilter in some cases |
256 | | if (code == 0xC0000374 || // STATUS_HEAP_CORRUPTION |
257 | | code == 0xC0000409 || // STATUS_STACK_BUFFER_OVERRUN (fast-fail) |
258 | | code == 0xC00000FD) { // STATUS_STACK_OVERFLOW |
259 | | // Call FlCrashDump directly for these special exceptions |
260 | | (void)FlCrashDump(ep); |
261 | | } |
262 | | |
263 | | // Let other exceptions pass to normal SEH handling |
264 | | return EXCEPTION_CONTINUE_SEARCH; |
265 | | } |
266 | | |
267 | | // Helper function to generate dump without exception context (for CRT handlers) |
268 | | static void FlCrashDumpNoException(const char* reason) { |
269 | | typedef BOOL(WINAPI * FxMiniDumpWriteDump)(IN HANDLE hProcess, IN DWORD ProcessId, IN HANDLE hFile, |
270 | | IN MINIDUMP_TYPE DumpType, |
271 | | IN CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, |
272 | | IN CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, |
273 | | IN CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam); |
274 | | |
275 | | HMODULE dll = LoadLibraryA("dbghelp.dll"); |
276 | | if (dll == NULL) return; |
277 | | FxMiniDumpWriteDump mdwd = (FxMiniDumpWriteDump)(GetProcAddress(dll, "MiniDumpWriteDump")); |
278 | | if (mdwd == NULL) { |
279 | | FreeLibrary(dll); |
280 | | return; |
281 | | } |
282 | | |
283 | | SYSTEMTIME st; |
284 | | GetLocalTime(&st); |
285 | | |
286 | | TdWchar exePath[MAX_PATH]; |
287 | | DWORD exeLen = GetModuleFileNameW(NULL, exePath, MAX_PATH); |
288 | | while (exeLen > 0 && exePath[exeLen - 1] != L'\\') exeLen--; |
289 | | exePath[exeLen] = L'\0'; |
290 | | |
291 | | TdWchar dmpPath[MAX_PATH]; |
292 | | _snwprintf_s(dmpPath, MAX_PATH, _TRUNCATE, |
293 | | L"%staosd_%04d%02d%02d_%02d%02d%02d.dmp", |
294 | | exePath, st.wYear, st.wMonth, st.wDay, |
295 | | st.wHour, st.wMinute, st.wSecond); |
296 | | |
297 | | HANDLE dmpFile = CreateFileW(dmpPath, GENERIC_WRITE, 0, NULL, |
298 | | CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); |
299 | | if (dmpFile != INVALID_HANDLE_VALUE) { |
300 | | MINIDUMP_TYPE dumpType = (MINIDUMP_TYPE)( |
301 | | MiniDumpWithDataSegs | MiniDumpWithProcessThreadData | |
302 | | MiniDumpWithHandleData | MiniDumpWithThreadInfo | MiniDumpWithFullMemoryInfo); |
303 | | (*mdwd)(GetCurrentProcess(), GetCurrentProcessId(), dmpFile, |
304 | | dumpType, NULL, NULL, NULL); // No exception info |
305 | | CloseHandle(dmpFile); |
306 | | } |
307 | | |
308 | | // Write reason to log file |
309 | | TdWchar logPath[MAX_PATH]; |
310 | | _snwprintf_s(logPath, MAX_PATH, _TRUNCATE, |
311 | | L"%staosd_%04d%02d%02d_%02d%02d%02d_stack.log", |
312 | | exePath, st.wYear, st.wMonth, st.wDay, |
313 | | st.wHour, st.wMinute, st.wSecond); |
314 | | HANDLE logFile = CreateFileW(logPath, GENERIC_WRITE, 0, NULL, |
315 | | CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); |
316 | | if (logFile != INVALID_HANDLE_VALUE) { |
317 | | char msg[512]; |
318 | | int n = _snprintf_s(msg, sizeof(msg), _TRUNCATE, |
319 | | "CRT/Runtime Error: %s\r\nThreadId: %lu\r\n", |
320 | | reason, (unsigned long)GetCurrentThreadId()); |
321 | | DWORD w = 0; |
322 | | if (n > 0) WriteFile(logFile, msg, (DWORD)n, &w, NULL); |
323 | | CloseHandle(logFile); |
324 | | } |
325 | | |
326 | | FreeLibrary(dll); |
327 | | } |
328 | | |
329 | | // CRT invalid parameter handler |
330 | | static void FlInvalidParameterHandler(const TdWchar* expression, const TdWchar* function, |
331 | | const TdWchar* file, unsigned int line, size_t reserved) { |
332 | | (void)expression; (void)function; (void)file; (void)line; (void)reserved; |
333 | | FlCrashDumpNoException("Invalid parameter detected in CRT function"); |
334 | | _exit(3); |
335 | | } |
336 | | |
337 | | // CRT pure virtual call handler |
338 | | static void FlPureCallHandler(void) { |
339 | | FlCrashDumpNoException("Pure virtual function call"); |
340 | | _exit(3); |
341 | | } |
342 | | |
343 | | // abort() handler - called when abort() is invoked |
344 | | static void FlAbortHandler(int sig) { |
345 | | (void)sig; |
346 | | FlCrashDumpNoException("abort() called"); |
347 | | _exit(3); |
348 | | } |
349 | | |
350 | | #elif defined(_TD_DARWIN_64) |
351 | | |
352 | | #include <errno.h> |
353 | | #include <libproc.h> |
354 | | #include <sys/sysctl.h> |
355 | | #include <SystemConfiguration/SCDynamicStoreCopySpecific.h> |
356 | | #include <CoreFoundation/CFString.h> |
357 | | #include <stdio.h> |
358 | | |
359 | | #else |
360 | | |
361 | | #include <argp.h> |
362 | | #ifndef TD_ASTRA |
363 | | #include <linux/sysctl.h> |
364 | | #include <sys/file.h> |
365 | | #include <sys/resource.h> |
366 | | #include <sys/statvfs.h> |
367 | | #include <sys/syscall.h> |
368 | | #endif |
369 | | #include <sys/utsname.h> |
370 | | #include <unistd.h> |
371 | | |
372 | | static pid_t tsProcId; |
373 | | static const char *tsSysNetFile = "/proc/net/dev"; |
374 | | static const char *tsSysCpuFile = "/proc/stat"; |
375 | | static const char *tsCpuPeriodFile = "/sys/fs/cgroup/cpu/cpu.cfs_period_us"; |
376 | | static const char *tsCpuQuotaFile = "/sys/fs/cgroup/cpu/cpu.cfs_quota_us"; |
377 | | static char tsProcCpuFile[25] = {0}; |
378 | | static char tsProcMemFile[25] = {0}; |
379 | | static char tsProcIOFile[25] = {0}; |
380 | | |
381 | | // cgroup v2 paths |
382 | | static const char *tsCgroupV2CpuMaxFile = "/sys/fs/cgroup/cpu.max"; |
383 | | static const char *tsCgroupV2MemMaxFile = "/sys/fs/cgroup/memory.max"; |
384 | | static const char *tsCgroupV2MemCurFile = "/sys/fs/cgroup/memory.current"; |
385 | | static const char *tsCgroupV2MemStatFile = "/sys/fs/cgroup/memory.stat"; |
386 | | static const char *tsCgroupV2CpuStatFile = "/sys/fs/cgroup/cpu.stat"; |
387 | | |
388 | | // cgroup v1 memory paths |
389 | | static const char *tsCgroupV1MemLimitFile = "/sys/fs/cgroup/memory/memory.limit_in_bytes"; |
390 | | static const char *tsCgroupV1MemUsageFile = "/sys/fs/cgroup/memory/memory.usage_in_bytes"; |
391 | | static const char *tsCgroupV1MemStatFile = "/sys/fs/cgroup/memory/memory.stat"; |
392 | | static const char *tsCgroupV1CpuAcctFile = "/sys/fs/cgroup/cpuacct/cpuacct.usage"; |
393 | | |
394 | | // Returns: 2 for cgroup v2, 1 for cgroup v1, 0 for no cgroup |
395 | 0 | static int32_t taosDetectCgroupVersion() { |
396 | 0 | static volatile int32_t cgroupVersion = -1; |
397 | |
|
398 | 0 | int32_t ver = atomic_load_32(&cgroupVersion); |
399 | 0 | if (ver >= 0) return ver; |
400 | | |
401 | 0 | if (taosCheckExistFile("/sys/fs/cgroup/cgroup.controllers")) { |
402 | 0 | ver = 2; |
403 | 0 | } else if (taosCheckExistFile(tsCpuQuotaFile) || taosCheckExistFile(tsCgroupV1MemLimitFile)) { |
404 | 0 | ver = 1; |
405 | 0 | } else { |
406 | 0 | ver = 0; |
407 | 0 | } |
408 | |
|
409 | 0 | (void)atomic_val_compare_exchange_32(&cgroupVersion, -1, ver); |
410 | 0 | return ver; |
411 | 0 | } |
412 | | |
413 | | // Read a single int64 value from a cgroup file. Returns 0 on success. |
414 | 0 | static int32_t taosReadCgroupInt64(const char *path, int64_t *value) { |
415 | 0 | if (path == NULL || value == NULL) return -1; |
416 | 0 | TdFilePtr pFile = taosOpenFile(path, TD_FILE_READ | TD_FILE_STREAM); |
417 | 0 | if (pFile == NULL) return -1; |
418 | | |
419 | 0 | char line[64] = {0}; |
420 | 0 | if (taosGetsFile(pFile, sizeof(line), line) <= 0) { |
421 | 0 | TAOS_SKIP_ERROR(taosCloseFile(&pFile)); |
422 | 0 | return -1; |
423 | 0 | } |
424 | 0 | TAOS_SKIP_ERROR(taosCloseFile(&pFile)); |
425 | | |
426 | | // "max" means no limit |
427 | 0 | if (strncmp(line, "max", 3) == 0) { |
428 | 0 | *value = INT64_MAX; |
429 | 0 | return 0; |
430 | 0 | } |
431 | | |
432 | 0 | char *endPtr = NULL; |
433 | 0 | int64_t v = taosStr2Int64(line, &endPtr, 10); |
434 | 0 | if (endPtr == line) return -1; |
435 | 0 | *value = v; |
436 | 0 | return 0; |
437 | 0 | } |
438 | | |
439 | 0 | static void taosGetProcIOnfos() { |
440 | 0 | tsPageSizeKB = sysconf(_SC_PAGESIZE) / 1024; |
441 | 0 | tsOpenMax = sysconf(_SC_OPEN_MAX); |
442 | 0 | tsStreamMax = TMAX(sysconf(_SC_STREAM_MAX), 0); |
443 | 0 | #ifndef TD_ASTRA |
444 | 0 | tsProcId = (pid_t)syscall(SYS_gettid); |
445 | |
|
446 | 0 | (void)snprintf(tsProcMemFile, sizeof(tsProcMemFile), "/proc/%d/status", tsProcId); |
447 | 0 | (void)snprintf(tsProcCpuFile, sizeof(tsProcCpuFile), "/proc/%d/stat", tsProcId); |
448 | 0 | (void)snprintf(tsProcIOFile, sizeof(tsProcIOFile), "/proc/%d/io", tsProcId); |
449 | 0 | #endif |
450 | 0 | } |
451 | | #endif |
452 | | |
453 | 0 | static int32_t taosGetSysCpuInfo(SysCpuInfo *cpuInfo) { |
454 | 0 | int32_t code = 0; |
455 | | #ifdef WINDOWS |
456 | | FILETIME pre_idleTime = {0}; |
457 | | FILETIME pre_kernelTime = {0}; |
458 | | FILETIME pre_userTime = {0}; |
459 | | FILETIME idleTime; |
460 | | FILETIME kernelTime; |
461 | | FILETIME userTime; |
462 | | bool res = GetSystemTimes(&idleTime, &kernelTime, &userTime); |
463 | | if (res) { |
464 | | cpuInfo->idle = CompareFileTime(&pre_idleTime, &idleTime); |
465 | | cpuInfo->system = CompareFileTime(&pre_kernelTime, &kernelTime); |
466 | | cpuInfo->user = CompareFileTime(&pre_userTime, &userTime); |
467 | | cpuInfo->nice = 0; |
468 | | } |
469 | | #elif defined(DARWIN) || defined(TD_ASTRA) |
470 | | cpuInfo->idle = 0; |
471 | | cpuInfo->system = 0; |
472 | | cpuInfo->user = 0; |
473 | | cpuInfo->nice = 0; |
474 | | #else |
475 | 0 | TdFilePtr pFile = taosOpenFile(tsSysCpuFile, TD_FILE_READ | TD_FILE_STREAM); |
476 | 0 | if (pFile == NULL) { |
477 | 0 | return terrno; |
478 | 0 | } |
479 | | |
480 | 0 | char line[1024]; |
481 | 0 | ssize_t bytes = taosGetsFile(pFile, sizeof(line), line); |
482 | 0 | if (bytes < 0) { |
483 | 0 | TAOS_SKIP_ERROR(taosCloseFile(&pFile)); |
484 | 0 | return terrno; |
485 | 0 | } |
486 | | |
487 | 0 | char cpu[10] = {0}; |
488 | 0 | code = sscanf(line, |
489 | 0 | "%s %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 |
490 | 0 | " %" PRIu64, |
491 | 0 | cpu, &cpuInfo->user, &cpuInfo->nice, &cpuInfo->system, &cpuInfo->idle, &cpuInfo->wa, &cpuInfo->hi, |
492 | 0 | &cpuInfo->si, &cpuInfo->st, &cpuInfo->guest, &cpuInfo->guest_nice); |
493 | 0 | if (EOF == code) { |
494 | 0 | terrno = TAOS_SYSTEM_ERROR(ERRNO); |
495 | 0 | TAOS_SKIP_ERROR(taosCloseFile(&pFile)); |
496 | 0 | return terrno; |
497 | 0 | } |
498 | | |
499 | 0 | TAOS_SKIP_ERROR(taosCloseFile(&pFile)); |
500 | 0 | #endif |
501 | |
|
502 | 0 | return 0; |
503 | 0 | } |
504 | | |
505 | 0 | static int32_t taosGetProcCpuInfo(ProcCpuInfo *cpuInfo) { |
506 | 0 | int32_t code = 0; |
507 | |
|
508 | | #ifdef WINDOWS |
509 | | FILETIME pre_krnlTm = {0}; |
510 | | FILETIME pre_usrTm = {0}; |
511 | | FILETIME creatTm, exitTm, krnlTm, usrTm; |
512 | | |
513 | | if (GetThreadTimes(GetCurrentThread(), &creatTm, &exitTm, &krnlTm, &usrTm)) { |
514 | | cpuInfo->stime = CompareFileTime(&pre_krnlTm, &krnlTm); |
515 | | cpuInfo->utime = CompareFileTime(&pre_usrTm, &usrTm); |
516 | | cpuInfo->cutime = 0; |
517 | | cpuInfo->cstime = 0; |
518 | | } |
519 | | #elif defined(DARWIN) || defined(TD_ASTRA) |
520 | | cpuInfo->stime = 0; |
521 | | cpuInfo->utime = 0; |
522 | | cpuInfo->cutime = 0; |
523 | | cpuInfo->cstime = 0; |
524 | | #else |
525 | 0 | TdFilePtr pFile = taosOpenFile(tsProcCpuFile, TD_FILE_READ | TD_FILE_STREAM); |
526 | 0 | if (pFile == NULL) { |
527 | 0 | return terrno; |
528 | 0 | } |
529 | | |
530 | 0 | char line[1024] = {0}; |
531 | 0 | ssize_t bytes = taosGetsFile(pFile, sizeof(line), line); |
532 | 0 | if (bytes < 0) { |
533 | 0 | TAOS_SKIP_ERROR(taosCloseFile(&pFile)); |
534 | 0 | return code; |
535 | 0 | } |
536 | | |
537 | 0 | for (int i = 0, blank = 0; line[i] != 0; ++i) { |
538 | 0 | if (line[i] == ' ') blank++; |
539 | 0 | if (blank == PROCESS_ITEM) { |
540 | 0 | code = sscanf(line + i + 1, "%" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64, &cpuInfo->utime, &cpuInfo->stime, |
541 | 0 | &cpuInfo->cutime, &cpuInfo->cstime); |
542 | 0 | if (EOF == code) { |
543 | 0 | terrno = TAOS_SYSTEM_ERROR(ERRNO); |
544 | 0 | return terrno; |
545 | 0 | } |
546 | | |
547 | 0 | break; |
548 | 0 | } |
549 | 0 | } |
550 | | |
551 | 0 | TAOS_SKIP_ERROR(taosCloseFile(&pFile)); |
552 | 0 | #endif |
553 | |
|
554 | 0 | return 0; |
555 | 0 | } |
556 | | |
557 | 0 | bool taosCheckSystemIsLittleEnd() { |
558 | 0 | union check { |
559 | 0 | int16_t i; |
560 | 0 | char ch[2]; |
561 | 0 | } c; |
562 | 0 | c.i = 1; |
563 | 0 | return c.ch[0] == 1; |
564 | 0 | } |
565 | | |
566 | 0 | void taosGetSystemInfo() { |
567 | | #ifdef WINDOWS |
568 | | TAOS_SKIP_ERROR(taosGetCpuCores(&tsNumOfCores, false)); |
569 | | TAOS_SKIP_ERROR(taosGetTotalMemory(&tsTotalMemoryKB)); |
570 | | TAOS_SKIP_ERROR(taosGetCpuUsage(NULL, NULL)); |
571 | | #elif defined(_TD_DARWIN_64) |
572 | | long physical_pages = sysconf(_SC_PHYS_PAGES); |
573 | | long page_size = sysconf(_SC_PAGESIZE); |
574 | | tsTotalMemoryKB = physical_pages * page_size / 1024; |
575 | | tsPageSizeKB = page_size / 1024; |
576 | | tsNumOfCores = sysconf(_SC_NPROCESSORS_ONLN); |
577 | | #elif defined(TD_ASTRA) |
578 | | taosGetProcIOnfos(); |
579 | | TAOS_SKIP_ERROR(taosGetCpuCores(&tsNumOfCores, false)); |
580 | | TAOS_SKIP_ERROR(taosGetTotalMemory(&tsTotalMemoryKB)); |
581 | | TAOS_SKIP_ERROR(taosGetCpuUsage(NULL, NULL)); |
582 | | #else |
583 | 0 | taosGetProcIOnfos(); |
584 | 0 | TAOS_SKIP_ERROR(taosGetCpuCores(&tsNumOfCores, false)); |
585 | 0 | TAOS_SKIP_ERROR(taosGetTotalMemory(&tsTotalMemoryKB)); |
586 | 0 | TAOS_SKIP_ERROR(taosGetCpuUsage(NULL, NULL)); |
587 | 0 | TAOS_SKIP_ERROR(taosGetCpuInstructions(&tsSSE42Supported, &tsAVXSupported, &tsAVX2Supported, &tsFMASupported, &tsAVX512Supported)); |
588 | 0 | #endif |
589 | 0 | } |
590 | | |
591 | 0 | int32_t taosGetEmail(char *email, int32_t maxLen) { |
592 | 0 | OS_PARAM_CHECK(email); |
593 | | #ifdef WINDOWS |
594 | | return 0; |
595 | | #elif defined(_TD_DARWIN_64) |
596 | | #ifdef CUS_PROMPT |
597 | | const char *filepath = "/usr/local/"CUS_PROMPT"/email"; |
598 | | #else |
599 | | const char *filepath = "/usr/local/taos/email"; |
600 | | #endif // CUS_PROMPT |
601 | | |
602 | | TdFilePtr pFile = taosOpenFile(filepath, TD_FILE_READ); |
603 | | if (pFile == NULL) return false; |
604 | | |
605 | | if (taosReadFile(pFile, (void *)email, maxLen) < 0) { |
606 | | taosCloseFile(&pFile); |
607 | | return terrno; |
608 | | } |
609 | | |
610 | | taosCloseFile(&pFile); |
611 | | return 0; |
612 | | #else |
613 | 0 | #ifdef CUS_PROMPT |
614 | 0 | const char *filepath = "/usr/local/"CUS_PROMPT"/email"; |
615 | | #else |
616 | | const char *filepath = "/usr/local/taos/email"; |
617 | | #endif // CUS_PROMPT |
618 | |
|
619 | 0 | TdFilePtr pFile = taosOpenFile(filepath, TD_FILE_READ); |
620 | 0 | if (pFile == NULL) return terrno; |
621 | | |
622 | 0 | if (taosReadFile(pFile, (void *)email, maxLen) < 0) { |
623 | 0 | int32_t code = terrno; |
624 | 0 | TAOS_SKIP_ERROR(taosCloseFile(&pFile)); |
625 | 0 | return code; |
626 | 0 | } |
627 | | |
628 | 0 | TAOS_SKIP_ERROR(taosCloseFile(&pFile)); |
629 | | |
630 | 0 | return 0; |
631 | 0 | #endif |
632 | 0 | } |
633 | | |
634 | | #ifdef WINDOWS |
635 | | bool getWinVersionReleaseName(char *releaseName, int32_t maxLen) { |
636 | | if(releaseName == NULL) return false; |
637 | | TCHAR szFileName[MAX_PATH]; |
638 | | DWORD dwHandle; |
639 | | DWORD dwLen; |
640 | | LPVOID lpData; |
641 | | UINT uLen; |
642 | | VS_FIXEDFILEINFO *pFileInfo; |
643 | | |
644 | | int ret = GetWindowsDirectory(szFileName, MAX_PATH); |
645 | | if (ret == 0) { |
646 | | return false; |
647 | | } |
648 | | wsprintf(szFileName, L"%s%s", szFileName, L"\\explorer.exe"); |
649 | | dwLen = GetFileVersionInfoSize(szFileName, &dwHandle); |
650 | | if (dwLen == 0) { |
651 | | return false; |
652 | | } |
653 | | |
654 | | lpData = malloc(dwLen); |
655 | | if (lpData == NULL) return false; |
656 | | if (!GetFileVersionInfo(szFileName, dwHandle, dwLen, lpData)) { |
657 | | free(lpData); |
658 | | return false; |
659 | | } |
660 | | |
661 | | if (!VerQueryValue(lpData, L"\\", (LPVOID *)&pFileInfo, &uLen)) { |
662 | | free(lpData); |
663 | | return false; |
664 | | } |
665 | | |
666 | | snprintf(releaseName, maxLen, "Windows %d.%d", HIWORD(pFileInfo->dwProductVersionMS), |
667 | | LOWORD(pFileInfo->dwProductVersionMS)); |
668 | | free(lpData); |
669 | | return true; |
670 | | } |
671 | | #endif |
672 | | |
673 | 0 | int32_t taosGetOsReleaseName(char *releaseName, char* sName, char* ver, int32_t maxLen) { |
674 | 0 | OS_PARAM_CHECK(releaseName); |
675 | | #ifdef WINDOWS |
676 | | if (!getWinVersionReleaseName(releaseName, maxLen)) { |
677 | | snprintf(releaseName, maxLen, "Windows"); |
678 | | } |
679 | | if(sName) snprintf(sName, maxLen, "Windows"); |
680 | | return 0; |
681 | | #elif defined(_TD_DARWIN_64) |
682 | | char osversion[32]; |
683 | | size_t osversion_len = sizeof(osversion) - 1; |
684 | | int osversion_name[] = { CTL_KERN, KERN_OSRELEASE }; |
685 | | |
686 | | if(sName) snprintf(sName, maxLen, "macOS"); |
687 | | if (sysctl(osversion_name, 2, osversion, &osversion_len, NULL, 0) == -1) { |
688 | | return TAOS_SYSTEM_ERROR(ERRNO); |
689 | | } |
690 | | |
691 | | uint32_t major, minor; |
692 | | if (sscanf(osversion, "%u.%u", &major, &minor) == EOF) { |
693 | | return TAOS_SYSTEM_ERROR(ERRNO); |
694 | | } |
695 | | if (major >= 20) { |
696 | | major -= 9; // macOS 11 and newer |
697 | | snprintf(releaseName, maxLen, "macOS %u.%u", major, minor); |
698 | | } else { |
699 | | major -= 4; // macOS 10.1.1 and newer |
700 | | snprintf(releaseName, maxLen, "macOS 10.%d.%d", major, minor); |
701 | | } |
702 | | |
703 | | return 0; |
704 | | #elif defined(TD_ASTRA) // TD_ASTRA_TODO |
705 | | if(sName) snprintf(sName, maxLen, "Astra"); |
706 | | snprintf(releaseName, maxLen, "Astra"); |
707 | | return 0; |
708 | | #else |
709 | 0 | char line[1024]; |
710 | 0 | char *dest = NULL; |
711 | 0 | size_t size = 0; |
712 | 0 | int32_t code = 0; |
713 | 0 | int32_t cnt = 0; |
714 | |
|
715 | 0 | TdFilePtr pFile = taosOpenFile("/etc/os-release", TD_FILE_READ | TD_FILE_STREAM); |
716 | 0 | if (pFile == NULL) { |
717 | 0 | return terrno; |
718 | 0 | } |
719 | | |
720 | 0 | while ((size = taosGetsFile(pFile, sizeof(line), line)) > 0) { |
721 | 0 | line[size - 1] = '\0'; |
722 | 0 | if (strncmp(line, "NAME", 4) == 0) { |
723 | 0 | dest = sName; |
724 | 0 | } else if (strncmp(line, "PRETTY_NAME", 11) == 0) { |
725 | 0 | dest = releaseName; |
726 | 0 | code = 0; |
727 | 0 | } else if (strncmp(line, "VERSION_ID", 10) == 0) { |
728 | 0 | dest = ver; |
729 | 0 | } else { |
730 | 0 | continue; |
731 | 0 | } |
732 | 0 | if (!dest) continue; |
733 | 0 | const char *p = strchr(line, '=') + 1; |
734 | 0 | if (*p == '"') { |
735 | 0 | p++; |
736 | 0 | line[size - 2] = 0; |
737 | 0 | } |
738 | 0 | tstrncpy(dest, p, maxLen); |
739 | |
|
740 | 0 | if (++cnt >= 3) break; |
741 | 0 | } |
742 | |
|
743 | 0 | TAOS_SKIP_ERROR(taosCloseFile(&pFile)); |
744 | 0 | return code; |
745 | 0 | #endif |
746 | 0 | } |
747 | | |
748 | 0 | int32_t taosGetCpuInfo(char *cpuModel, int32_t maxLen, float *numOfCores) { |
749 | 0 | OS_PARAM_CHECK(cpuModel); |
750 | 0 | OS_PARAM_CHECK(numOfCores); |
751 | | #ifdef WINDOWS |
752 | | char value[100]; |
753 | | DWORD bufferSize = sizeof(value); |
754 | | LSTATUS ret = RegGetValue(HKEY_LOCAL_MACHINE, "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", "ProcessorNameString", |
755 | | RRF_RT_ANY, NULL, (PVOID)&value, &bufferSize); |
756 | | if (ret != ERROR_SUCCESS) { |
757 | | return TAOS_SYSTEM_ERROR(ret); |
758 | | } |
759 | | tstrncpy(cpuModel, value, maxLen); |
760 | | SYSTEM_INFO si; |
761 | | memset(&si, 0, sizeof(SYSTEM_INFO)); |
762 | | GetSystemInfo(&si); |
763 | | *numOfCores = si.dwNumberOfProcessors; |
764 | | return 0; |
765 | | #elif defined(_TD_DARWIN_64) |
766 | | char buf[16]; |
767 | | int32_t done = 0; |
768 | | int32_t code = -1; |
769 | | |
770 | | TdCmdPtr pCmd = taosOpenCmd("sysctl -n machdep.cpu.brand_string"); |
771 | | if (pCmd == NULL) return code; |
772 | | if (taosGetsCmd(pCmd, maxLen, cpuModel) > 0) { |
773 | | code = 0; |
774 | | done |= 1; |
775 | | } |
776 | | int endPos = strlen(cpuModel)-1; |
777 | | if (cpuModel[endPos] == '\n') { |
778 | | cpuModel[endPos] = '\0'; |
779 | | } |
780 | | taosCloseCmd(&pCmd); |
781 | | |
782 | | pCmd = taosOpenCmd("sysctl -n machdep.cpu.core_count"); |
783 | | if (pCmd == NULL) return code; |
784 | | memset(buf, 0, sizeof(buf)); |
785 | | if (taosGetsCmd(pCmd, sizeof(buf) - 1, buf) > 0) { |
786 | | code = 0; |
787 | | done |= 2; |
788 | | *numOfCores = taosStr2Float(buf, NULL); |
789 | | } |
790 | | taosCloseCmd(&pCmd); |
791 | | |
792 | | return code; |
793 | | #elif defined(TD_ASTRA) // TD_ASTRA_TODO |
794 | | tstrncpy(cpuModel, "ft_2000_4", maxLen); |
795 | | TAOS_SKIP_ERROR(taosGetCpuCores(numOfCores, false)); |
796 | | return 0; |
797 | | #else |
798 | 0 | char line[1024] = {0}; |
799 | 0 | size_t size = 0; |
800 | 0 | int32_t done = 0; |
801 | 0 | int32_t code = 0; |
802 | 0 | float coreCount = 0; |
803 | |
|
804 | 0 | TdFilePtr pFile = taosOpenFile("/proc/cpuinfo", TD_FILE_READ | TD_FILE_STREAM); |
805 | 0 | if (pFile == NULL) return terrno; |
806 | | |
807 | 0 | while (done != 3 && (size = taosGetsFile(pFile, sizeof(line), line)) > 0) { |
808 | 0 | line[size - 1] = '\0'; |
809 | 0 | if (((done & 1) == 0) && strncmp(line, "model name", 10) == 0) { |
810 | 0 | const char *v = strchr(line, ':') + 2; |
811 | 0 | tstrncpy(cpuModel, v, maxLen); |
812 | 0 | code = 0; |
813 | 0 | done |= 1; |
814 | 0 | } else if (((done & 2) == 0) && strncmp(line, "cpu cores", 9) == 0) { |
815 | 0 | const char *v = strchr(line, ':') + 2; |
816 | 0 | *numOfCores = taosStr2Float(v, NULL); |
817 | 0 | done |= 2; |
818 | 0 | } |
819 | 0 | if (strncmp(line, "processor", 9) == 0) coreCount += 1; |
820 | 0 | } |
821 | |
|
822 | 0 | TAOS_SKIP_ERROR(taosCloseFile(&pFile)); |
823 | |
|
824 | 0 | if (code != 0 && (done & 1) == 0) { |
825 | 0 | TdFilePtr pFile1 = taosOpenFile("/proc/device-tree/model", TD_FILE_READ | TD_FILE_STREAM); |
826 | 0 | if (pFile1 != NULL) { |
827 | 0 | ssize_t bytes = taosGetsFile(pFile1, maxLen, cpuModel); |
828 | 0 | TAOS_SKIP_ERROR(taosCloseFile(&pFile)); |
829 | 0 | if (bytes > 0) { |
830 | 0 | code = 0; |
831 | 0 | done |= 1; |
832 | 0 | } |
833 | 0 | } |
834 | 0 | } |
835 | |
|
836 | 0 | if (code != 0 && (done & 1) == 0) { |
837 | 0 | TdCmdPtr pCmd = taosOpenCmd("uname -a"); |
838 | 0 | if (pCmd == NULL) { |
839 | 0 | return terrno; |
840 | 0 | } |
841 | 0 | if (taosGetsCmd(pCmd, maxLen, cpuModel) > 0) { |
842 | 0 | code = 0; |
843 | 0 | done |= 1; |
844 | 0 | } |
845 | 0 | taosCloseCmd(&pCmd); |
846 | 0 | } |
847 | | |
848 | 0 | if ((done & 2) == 0) { |
849 | 0 | *numOfCores = coreCount; |
850 | 0 | done |= 2; |
851 | 0 | } |
852 | |
|
853 | 0 | return code; |
854 | 0 | #endif |
855 | 0 | } |
856 | | |
857 | | #if !defined(WINDOWS) && !defined(_TD_DARWIN_64) && !defined(TD_ASTRA) |
858 | | // Try cgroup v2 cpu.max: format "$MAX $PERIOD" or "max $PERIOD" |
859 | 0 | static int32_t taosCntrGetCpuCoresV2(float *numOfCores) { |
860 | 0 | TdFilePtr pFile = taosOpenFile(tsCgroupV2CpuMaxFile, TD_FILE_READ | TD_FILE_STREAM); |
861 | 0 | if (pFile == NULL) return -1; |
862 | | |
863 | 0 | char line[64] = {0}; |
864 | 0 | if (taosGetsFile(pFile, sizeof(line), line) <= 0) { |
865 | 0 | TAOS_SKIP_ERROR(taosCloseFile(&pFile)); |
866 | 0 | return -1; |
867 | 0 | } |
868 | 0 | TAOS_SKIP_ERROR(taosCloseFile(&pFile)); |
869 | | |
870 | | // "max" means no CPU limit |
871 | 0 | if (strncmp(line, "max", 3) == 0) { |
872 | 0 | return -1; |
873 | 0 | } |
874 | | |
875 | 0 | int64_t quota = 0, period = 0; |
876 | 0 | if (sscanf(line, "%" PRId64 " %" PRId64, "a, &period) != 2 || period <= 0 || quota <= 0) { |
877 | 0 | return -1; |
878 | 0 | } |
879 | | |
880 | 0 | double quotaCores = (double)quota / (double)period; |
881 | 0 | double sysCores = (double)sysconf(_SC_NPROCESSORS_ONLN); |
882 | 0 | *numOfCores = (float)((quotaCores < sysCores && quotaCores > 0) ? quotaCores : sysCores); |
883 | 0 | return (*numOfCores > 0) ? 0 : -1; |
884 | 0 | } |
885 | | |
886 | | // Try cgroup v1 cpu.cfs_quota_us / cpu.cfs_period_us |
887 | 0 | static int32_t taosCntrGetCpuCoresV1(float *numOfCores) { |
888 | 0 | TdFilePtr pFile = NULL; |
889 | 0 | if (!(pFile = taosOpenFile(tsCpuQuotaFile, TD_FILE_READ | TD_FILE_STREAM))) { |
890 | 0 | return -1; |
891 | 0 | } |
892 | 0 | char qline[32] = {0}; |
893 | 0 | if (taosGetsFile(pFile, sizeof(qline), qline) <= 0) { |
894 | 0 | TAOS_SKIP_ERROR(taosCloseFile(&pFile)); |
895 | 0 | return -1; |
896 | 0 | } |
897 | 0 | TAOS_SKIP_ERROR(taosCloseFile(&pFile)); |
898 | |
|
899 | 0 | int64_t quota = taosStr2Int64(qline, NULL, 10); |
900 | 0 | if (quota < 0) { |
901 | 0 | return -1; |
902 | 0 | } |
903 | | |
904 | 0 | if (!(pFile = taosOpenFile(tsCpuPeriodFile, TD_FILE_READ | TD_FILE_STREAM))) { |
905 | 0 | return -1; |
906 | 0 | } |
907 | 0 | char pline[32] = {0}; |
908 | 0 | if (taosGetsFile(pFile, sizeof(pline), pline) <= 0) { |
909 | 0 | TAOS_SKIP_ERROR(taosCloseFile(&pFile)); |
910 | 0 | return -1; |
911 | 0 | } |
912 | 0 | TAOS_SKIP_ERROR(taosCloseFile(&pFile)); |
913 | |
|
914 | 0 | int64_t period = taosStr2Int64(pline, NULL, 10); |
915 | 0 | if (period <= 0) return -1; |
916 | | |
917 | 0 | double quotaCores = (double)quota / (double)period; |
918 | 0 | double sysCores = (double)sysconf(_SC_NPROCESSORS_ONLN); |
919 | 0 | *numOfCores = (float)((quotaCores < sysCores && quotaCores > 0) ? quotaCores : sysCores); |
920 | 0 | return (*numOfCores > 0) ? 0 : -1; |
921 | 0 | } |
922 | | #endif // !WINDOWS && !_TD_DARWIN_64 && !TD_ASTRA |
923 | | |
924 | | // Returns the container's CPU quota if successful, otherwise returns the physical CPU cores |
925 | 0 | static int32_t taosCntrGetCpuCores(float *numOfCores) { |
926 | | #ifdef WINDOWS |
927 | | return TSDB_CODE_UNSUPPORT_OS; |
928 | | #elif defined(_TD_DARWIN_64) || defined(TD_ASTRA) |
929 | | return TSDB_CODE_UNSUPPORT_OS; |
930 | | #else |
931 | 0 | int32_t cgroupVer = taosDetectCgroupVersion(); |
932 | |
|
933 | 0 | if (cgroupVer == 2 && taosCntrGetCpuCoresV2(numOfCores) == 0) { |
934 | 0 | return 0; |
935 | 0 | } |
936 | 0 | if (cgroupVer >= 1 && taosCntrGetCpuCoresV1(numOfCores) == 0) { |
937 | 0 | return 0; |
938 | 0 | } |
939 | | |
940 | 0 | *numOfCores = sysconf(_SC_NPROCESSORS_ONLN); |
941 | 0 | if(*numOfCores <= 0) { |
942 | 0 | return TAOS_SYSTEM_ERROR(ERRNO); |
943 | 0 | } |
944 | 0 | return 0; |
945 | 0 | #endif |
946 | 0 | } |
947 | | |
948 | 0 | int32_t taosGetCpuCores(float *numOfCores, bool physical) { |
949 | 0 | OS_PARAM_CHECK(numOfCores); |
950 | | #ifdef WINDOWS |
951 | | SYSTEM_INFO info; |
952 | | GetSystemInfo(&info); |
953 | | *numOfCores = info.dwNumberOfProcessors; |
954 | | return 0; |
955 | | #elif defined(_TD_DARWIN_64) |
956 | | *numOfCores = sysconf(_SC_NPROCESSORS_ONLN); |
957 | | if(*numOfCores <= 0) { |
958 | | return TAOS_SYSTEM_ERROR(ERRNO); |
959 | | } |
960 | | return 0; |
961 | | #elif defined(TD_ASTRA) // TD_ASTRA_TODO |
962 | | *numOfCores = 4; |
963 | | return 0; |
964 | | #else |
965 | 0 | if (physical) { |
966 | 0 | *numOfCores = sysconf(_SC_NPROCESSORS_ONLN); |
967 | 0 | if(*numOfCores <= 0) { |
968 | 0 | return TAOS_SYSTEM_ERROR(ERRNO); |
969 | 0 | } |
970 | 0 | } else { |
971 | 0 | int code= taosCntrGetCpuCores(numOfCores); |
972 | 0 | if(code != 0) { |
973 | 0 | return code; |
974 | 0 | } |
975 | 0 | } |
976 | 0 | return 0; |
977 | 0 | #endif |
978 | 0 | } |
979 | | |
980 | | #if !defined(WINDOWS) && !defined(_TD_DARWIN_64) && !defined(TD_ASTRA) |
981 | | // Read cgroup CPU usage in microseconds. Returns 0 on success. |
982 | 0 | static int32_t taosGetCgroupCpuUsageUsec(int64_t *usageUsec) { |
983 | 0 | if (usageUsec == NULL) return -1; |
984 | | |
985 | 0 | int32_t cgroupVer = taosDetectCgroupVersion(); |
986 | 0 | if (cgroupVer == 2) { |
987 | | // cgroup v2: cpu.stat has "usage_usec <value>" |
988 | 0 | TdFilePtr pFile = taosOpenFile(tsCgroupV2CpuStatFile, TD_FILE_READ | TD_FILE_STREAM); |
989 | 0 | if (pFile == NULL) return -1; |
990 | 0 | char line[256] = {0}; |
991 | 0 | while (taosGetsFile(pFile, sizeof(line), line) > 0) { |
992 | 0 | if (strncmp(line, "usage_usec", 10) == 0) { |
993 | 0 | if (sscanf(line + 10, " %" PRId64, usageUsec) != 1) { |
994 | 0 | TAOS_SKIP_ERROR(taosCloseFile(&pFile)); |
995 | 0 | return -1; |
996 | 0 | } |
997 | 0 | TAOS_SKIP_ERROR(taosCloseFile(&pFile)); |
998 | 0 | return 0; |
999 | 0 | } |
1000 | 0 | } |
1001 | 0 | TAOS_SKIP_ERROR(taosCloseFile(&pFile)); |
1002 | 0 | return -1; |
1003 | 0 | } else if (cgroupVer == 1) { |
1004 | | // cgroup v1: cpuacct.usage is in nanoseconds |
1005 | 0 | int64_t usageNs = 0; |
1006 | 0 | if (taosReadCgroupInt64(tsCgroupV1CpuAcctFile, &usageNs) == 0) { |
1007 | 0 | *usageUsec = usageNs / 1000; |
1008 | 0 | return 0; |
1009 | 0 | } |
1010 | 0 | return -1; |
1011 | 0 | } |
1012 | 0 | return -1; |
1013 | 0 | } |
1014 | | #endif // !WINDOWS && !_TD_DARWIN_64 && !TD_ASTRA |
1015 | | |
1016 | 0 | int32_t taosGetCpuUsage(double *cpu_system, double *cpu_engine) { |
1017 | 0 | static int64_t lastSysUsed = -1; |
1018 | 0 | static int64_t lastSysTotal = -1; |
1019 | 0 | static int64_t lastProcTotal = -1; |
1020 | 0 | static int64_t curSysUsed = 0; |
1021 | 0 | static int64_t curSysTotal = 0; |
1022 | 0 | static int64_t curProcTotal = 0; |
1023 | 0 | #if !defined(WINDOWS) && !defined(_TD_DARWIN_64) && !defined(TD_ASTRA) |
1024 | 0 | static int64_t lastCgroupUsageUsec = -1; |
1025 | 0 | static int64_t lastWallTimeUsec = -1; |
1026 | 0 | #endif |
1027 | |
|
1028 | 0 | if (cpu_system != NULL) *cpu_system = 0; |
1029 | 0 | if (cpu_engine != NULL) *cpu_engine = 0; |
1030 | |
|
1031 | 0 | bool cgroupUsed = false; |
1032 | |
|
1033 | 0 | #if !defined(WINDOWS) && !defined(_TD_DARWIN_64) && !defined(TD_ASTRA) |
1034 | | // Try container-aware CPU usage first |
1035 | 0 | int32_t cgroupVer = taosDetectCgroupVersion(); |
1036 | 0 | int64_t cgroupUsageUsec = 0; |
1037 | |
|
1038 | 0 | if (cgroupVer > 0 && taosGetCgroupCpuUsageUsec(&cgroupUsageUsec) == 0) { |
1039 | 0 | struct timespec ts; |
1040 | 0 | if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) goto _proc_stat; |
1041 | 0 | int64_t wallTimeUsec = (int64_t)ts.tv_sec * 1000000 + ts.tv_nsec / 1000; |
1042 | |
|
1043 | 0 | if (lastCgroupUsageUsec >= 0 && lastWallTimeUsec >= 0) { |
1044 | 0 | int64_t deltaUsage = cgroupUsageUsec - lastCgroupUsageUsec; |
1045 | 0 | int64_t deltaWall = wallTimeUsec - lastWallTimeUsec; |
1046 | 0 | if (deltaWall > 0 && deltaUsage >= 0) { |
1047 | 0 | float numCores = 0; |
1048 | 0 | TAOS_SKIP_ERROR(taosGetCpuCores(&numCores, false)); |
1049 | 0 | if (numCores <= 0) numCores = 1; |
1050 | 0 | if (cpu_system != NULL) { |
1051 | 0 | *cpu_system = (double)deltaUsage / (double)deltaWall / numCores * 100.0; |
1052 | 0 | if (*cpu_system > 100.0) *cpu_system = 100.0; |
1053 | 0 | } |
1054 | 0 | cgroupUsed = true; |
1055 | 0 | } |
1056 | 0 | } |
1057 | 0 | lastCgroupUsageUsec = cgroupUsageUsec; |
1058 | 0 | lastWallTimeUsec = wallTimeUsec; |
1059 | 0 | } |
1060 | | |
1061 | 0 | _proc_stat: |
1062 | 0 | ; |
1063 | 0 | #endif |
1064 | |
|
1065 | 0 | SysCpuInfo sysCpu = {0}; |
1066 | 0 | ProcCpuInfo procCpu = {0}; |
1067 | 0 | if (taosGetSysCpuInfo(&sysCpu) == 0 && taosGetProcCpuInfo(&procCpu) == 0) { |
1068 | 0 | curSysUsed = sysCpu.user + sysCpu.nice + sysCpu.system + sysCpu.wa + sysCpu.hi + sysCpu.si + sysCpu.st + |
1069 | 0 | sysCpu.guest + sysCpu.guest_nice; |
1070 | 0 | curSysTotal = curSysUsed + sysCpu.idle; |
1071 | 0 | curProcTotal = procCpu.utime + procCpu.stime + procCpu.cutime + procCpu.cstime; |
1072 | |
|
1073 | 0 | if(lastSysUsed >= 0 && lastSysTotal >=0 && lastProcTotal >=0){ |
1074 | 0 | if (curSysTotal - lastSysTotal > 0 && curSysUsed >= lastSysUsed && curProcTotal >= lastProcTotal) { |
1075 | 0 | if (!cgroupUsed && cpu_system != NULL) { |
1076 | 0 | *cpu_system = (curSysUsed - lastSysUsed) / (double)(curSysTotal - lastSysTotal) * 100; |
1077 | 0 | } |
1078 | 0 | if (cpu_engine != NULL) { |
1079 | 0 | *cpu_engine = (curProcTotal - lastProcTotal) / (double)(curSysTotal - lastSysTotal) * 100; |
1080 | 0 | } |
1081 | 0 | } |
1082 | 0 | } |
1083 | |
|
1084 | 0 | lastSysUsed = curSysUsed; |
1085 | 0 | lastSysTotal = curSysTotal; |
1086 | 0 | lastProcTotal = curProcTotal; |
1087 | 0 | } |
1088 | 0 | return 0; |
1089 | 0 | } |
1090 | | |
1091 | | #define __cpuid_fix(level, a, b, c, d) \ |
1092 | 0 | __asm__("xor %%ecx, %%ecx\n" \ |
1093 | 0 | "cpuid\n" \ |
1094 | 0 | : "=a"(a), "=b"(b), "=c"(c), "=d"(d) \ |
1095 | 0 | : "0"(level)) |
1096 | | |
1097 | | // todo add for windows and mac |
1098 | 0 | int32_t taosGetCpuInstructions(char* sse42, char* avx, char* avx2, char* fma, char* avx512) { |
1099 | | #ifdef WINDOWS |
1100 | | #elif defined(_TD_DARWIN_64) |
1101 | | #else |
1102 | |
|
1103 | 0 | #ifdef _TD_X86_ |
1104 | | // Since the compiler is not support avx/avx2 instructions, the global variables always need to be |
1105 | | // set to be false |
1106 | 0 | uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0; |
1107 | |
|
1108 | 0 | int32_t ret = __get_cpuid(1, &eax, &ebx, &ecx, &edx); |
1109 | 0 | if (ret == 0) { |
1110 | 0 | return -1; // failed to get the cpuid info |
1111 | 0 | } |
1112 | | |
1113 | 0 | *sse42 = (char) ((ecx & bit_SSE4_2) == bit_SSE4_2); |
1114 | 0 | *avx = (char) ((ecx & bit_AVX) == bit_AVX); |
1115 | 0 | *fma = (char) ((ecx & bit_FMA) == bit_FMA); |
1116 | | |
1117 | | // work around a bug in GCC. |
1118 | | // Ref to https://gcc.gnu.org/bugzilla/show_bug.cgi?id=77756 |
1119 | 0 | __cpuid_fix(7u, eax, ebx, ecx, edx); |
1120 | 0 | *avx2 = (char) ((ebx & bit_AVX2) == bit_AVX2); |
1121 | 0 | *avx512 = (char)((ebx & bit_AVX512F) == bit_AVX512F); |
1122 | 0 | #endif // _TD_X86_ |
1123 | 0 | #endif |
1124 | |
|
1125 | 0 | return 0; |
1126 | 0 | } |
1127 | | |
1128 | 0 | int32_t taosGetTotalMemory(int64_t *totalKB) { |
1129 | 0 | OS_PARAM_CHECK(totalKB); |
1130 | | #ifdef WINDOWS |
1131 | | MEMORYSTATUSEX memsStat; |
1132 | | memsStat.dwLength = sizeof(memsStat); |
1133 | | if (!GlobalMemoryStatusEx(&memsStat)) { |
1134 | | return TAOS_SYSTEM_WINAPI_ERROR(GetLastError()); |
1135 | | } |
1136 | | |
1137 | | *totalKB = memsStat.ullTotalPhys / 1024; |
1138 | | return 0; |
1139 | | #elif defined(_TD_DARWIN_64) |
1140 | | return 0; |
1141 | | #elif defined(TD_ASTRA) // TD_ASTRA_TODO |
1142 | | *totalKB = (int64_t)256 * 1024; |
1143 | | return 0; |
1144 | | #else |
1145 | 0 | int64_t pageSizeKB = tsPageSizeKB; |
1146 | 0 | if (pageSizeKB <= 0) { |
1147 | 0 | pageSizeKB = sysconf(_SC_PAGESIZE) / 1024; |
1148 | 0 | } |
1149 | 0 | *totalKB = (int64_t)(sysconf(_SC_PHYS_PAGES) * pageSizeKB); |
1150 | 0 | if(*totalKB <= 0) { |
1151 | 0 | return TAOS_SYSTEM_ERROR(ERRNO); |
1152 | 0 | } |
1153 | | |
1154 | | // Apply cgroup memory limit if available |
1155 | 0 | int32_t cgroupVer = taosDetectCgroupVersion(); |
1156 | 0 | int64_t cgroupLimitBytes = INT64_MAX; |
1157 | 0 | if (cgroupVer == 2) { |
1158 | 0 | TAOS_SKIP_ERROR(taosReadCgroupInt64(tsCgroupV2MemMaxFile, &cgroupLimitBytes)); |
1159 | 0 | } else if (cgroupVer == 1) { |
1160 | 0 | TAOS_SKIP_ERROR(taosReadCgroupInt64(tsCgroupV1MemLimitFile, &cgroupLimitBytes)); |
1161 | 0 | } |
1162 | 0 | if (cgroupLimitBytes > 0 && cgroupLimitBytes < INT64_MAX) { |
1163 | 0 | int64_t cgroupLimitKB = cgroupLimitBytes / 1024; |
1164 | 0 | if (cgroupLimitKB > 0 && cgroupLimitKB < *totalKB) { |
1165 | 0 | *totalKB = cgroupLimitKB; |
1166 | 0 | } |
1167 | 0 | } |
1168 | |
|
1169 | 0 | return 0; |
1170 | 0 | #endif |
1171 | 0 | } |
1172 | | |
1173 | 0 | int32_t taosGetProcMemory(int64_t *usedKB) { |
1174 | 0 | OS_PARAM_CHECK(usedKB); |
1175 | | #ifdef WINDOWS |
1176 | | unsigned bytes_used = 0; |
1177 | | |
1178 | | #if defined(_WIN64) && defined(_MSC_VER) |
1179 | | PROCESS_MEMORY_COUNTERS pmc; |
1180 | | HANDLE cur_proc = GetCurrentProcess(); |
1181 | | |
1182 | | if (GetProcessMemoryInfo(cur_proc, &pmc, sizeof(pmc))) { |
1183 | | bytes_used = (unsigned)(pmc.WorkingSetSize + pmc.PagefileUsage); |
1184 | | } |
1185 | | #endif |
1186 | | |
1187 | | *usedKB = bytes_used / 1024; |
1188 | | return 0; |
1189 | | #elif defined(_TD_DARWIN_64) || defined(TD_ASTRA) |
1190 | | *usedKB = 0; |
1191 | | return 0; |
1192 | | #else |
1193 | 0 | TdFilePtr pFile = taosOpenFile(tsProcMemFile, TD_FILE_READ | TD_FILE_STREAM); |
1194 | 0 | if (pFile == NULL) { |
1195 | | // printf("open file:%s failed", tsProcMemFile); |
1196 | 0 | return terrno; |
1197 | 0 | } |
1198 | | |
1199 | 0 | ssize_t bytes = 0; |
1200 | 0 | char line[1024] = {0}; |
1201 | 0 | while (!taosEOFFile(pFile)) { |
1202 | 0 | bytes = taosGetsFile(pFile, sizeof(line), line); |
1203 | 0 | if (bytes <= 0) { |
1204 | 0 | break; |
1205 | 0 | } |
1206 | 0 | if (strstr(line, "VmRSS:") != NULL) { |
1207 | 0 | break; |
1208 | 0 | } |
1209 | 0 | } |
1210 | |
|
1211 | 0 | char tmp[10]; |
1212 | 0 | (void)sscanf(line, "%s %" PRId64, tmp, usedKB); |
1213 | |
|
1214 | 0 | TAOS_SKIP_ERROR(taosCloseFile(&pFile)); |
1215 | | |
1216 | 0 | return 0; |
1217 | 0 | #endif |
1218 | 0 | } |
1219 | | |
1220 | 0 | int32_t taosGetSysAvailMemory(int64_t *availSize) { |
1221 | | #ifdef WINDOWS |
1222 | | MEMORYSTATUSEX memsStat; |
1223 | | memsStat.dwLength = sizeof(memsStat); |
1224 | | if (!GlobalMemoryStatusEx(&memsStat)) { |
1225 | | return -1; |
1226 | | } |
1227 | | |
1228 | | int64_t nMemFree = memsStat.ullAvailPhys; |
1229 | | int64_t nMemTotal = memsStat.ullTotalPhys; |
1230 | | |
1231 | | *availSize = nMemTotal - nMemFree; |
1232 | | return 0; |
1233 | | #elif defined(_TD_DARWIN_64) || defined(TD_ASTRA) |
1234 | | *availSize = 0; |
1235 | | return 0; |
1236 | | #else |
1237 | | // Try cgroup-aware available memory first |
1238 | 0 | int32_t cgroupVer = taosDetectCgroupVersion(); |
1239 | 0 | int64_t cgroupLimit = 0; |
1240 | 0 | int64_t cgroupCurrent = 0; |
1241 | |
|
1242 | 0 | if (cgroupVer == 2) { |
1243 | 0 | if (taosReadCgroupInt64(tsCgroupV2MemMaxFile, &cgroupLimit) == 0 && |
1244 | 0 | taosReadCgroupInt64(tsCgroupV2MemCurFile, &cgroupCurrent) == 0 && |
1245 | 0 | cgroupLimit > 0 && cgroupLimit < INT64_MAX) { |
1246 | 0 | *availSize = (cgroupLimit > cgroupCurrent) ? (cgroupLimit - cgroupCurrent) : 0; |
1247 | 0 | return 0; |
1248 | 0 | } |
1249 | 0 | } else if (cgroupVer == 1) { |
1250 | | // v1 uses a huge sentinel (near INT64_MAX) for "no limit"; also compare against physical memory |
1251 | 0 | int64_t physMemBytes = (int64_t)sysconf(_SC_PHYS_PAGES) * sysconf(_SC_PAGESIZE); |
1252 | 0 | if (taosReadCgroupInt64(tsCgroupV1MemLimitFile, &cgroupLimit) == 0 && |
1253 | 0 | taosReadCgroupInt64(tsCgroupV1MemUsageFile, &cgroupCurrent) == 0 && |
1254 | 0 | cgroupLimit > 0 && cgroupLimit < INT64_MAX && cgroupLimit < physMemBytes) { |
1255 | 0 | *availSize = (cgroupLimit > cgroupCurrent) ? (cgroupLimit - cgroupCurrent) : 0; |
1256 | 0 | return 0; |
1257 | 0 | } |
1258 | 0 | } |
1259 | | |
1260 | | // Fallback to /proc/meminfo |
1261 | 0 | TdFilePtr pFile = taosOpenFile("/proc/meminfo", TD_FILE_READ | TD_FILE_STREAM); |
1262 | 0 | if (pFile == NULL) { |
1263 | 0 | return terrno; |
1264 | 0 | } |
1265 | | |
1266 | 0 | ssize_t bytes = 0; |
1267 | 0 | char line[128] = {0}; |
1268 | 0 | int32_t expectedSize = 13; //"MemAvailable:" |
1269 | 0 | while (!taosEOFFile(pFile)) { |
1270 | 0 | bytes = taosGetsFile(pFile, sizeof(line), line); |
1271 | 0 | if (bytes < 0) { |
1272 | 0 | break; |
1273 | 0 | } |
1274 | 0 | if (line[0] != 'M' && line[3] != 'A') { |
1275 | 0 | line[0] = 0; |
1276 | 0 | continue; |
1277 | 0 | } |
1278 | 0 | if (0 == strncmp(line, "MemAvailable:", expectedSize)) { |
1279 | 0 | break; |
1280 | 0 | } |
1281 | 0 | } |
1282 | |
|
1283 | 0 | if (0 == line[0]) { |
1284 | 0 | return TSDB_CODE_UNSUPPORT_OS; |
1285 | 0 | } |
1286 | | |
1287 | 0 | char tmp[32]; |
1288 | 0 | (void)sscanf(line, "%s %" PRId64, tmp, availSize); |
1289 | |
|
1290 | 0 | *availSize *= 1024; |
1291 | | |
1292 | 0 | (void)taosCloseFile(&pFile); |
1293 | 0 | return 0; |
1294 | 0 | #endif |
1295 | 0 | } |
1296 | | |
1297 | 0 | static void taosGetMemValue(char* line, char* key, int64_t* value){ |
1298 | 0 | if(value == NULL) return; |
1299 | 0 | *value = 0; |
1300 | 0 | if(line == NULL || line[0] == '\0') return; |
1301 | | |
1302 | 0 | char *colon_pos = strchr(line, ':'); |
1303 | 0 | if (colon_pos != NULL) { |
1304 | 0 | *colon_pos = '\0'; |
1305 | 0 | if(sscanf(line, "%s", key) != 1){ |
1306 | 0 | key[0] = '\0'; |
1307 | 0 | } |
1308 | 0 | if (sscanf(colon_pos + 1, "%" PRId64, value) != 1) { |
1309 | 0 | *value = 0; |
1310 | 0 | } |
1311 | 0 | } |
1312 | 0 | } |
1313 | | |
1314 | | // Read "inactive_file" from cgroup memory.stat |
1315 | 0 | static int64_t taosGetCgroupMemCache(const char *statFile) { |
1316 | 0 | TdFilePtr pFile = taosOpenFile(statFile, TD_FILE_READ | TD_FILE_STREAM); |
1317 | 0 | if (pFile == NULL) return 0; |
1318 | | |
1319 | 0 | char line[256] = {0}; |
1320 | 0 | int64_t inactiveFile = 0; |
1321 | 0 | while (taosGetsFile(pFile, sizeof(line), line) > 0) { |
1322 | 0 | if (strncmp(line, "inactive_file", 13) == 0) { |
1323 | 0 | if (sscanf(line + 13, " %" PRId64, &inactiveFile) == 1) break; |
1324 | 0 | } |
1325 | | // cgroup v1 uses "total_inactive_file" |
1326 | 0 | if (strncmp(line, "total_inactive_file", 19) == 0) { |
1327 | 0 | if (sscanf(line + 19, " %" PRId64, &inactiveFile) == 1) break; |
1328 | 0 | } |
1329 | 0 | } |
1330 | 0 | TAOS_SKIP_ERROR(taosCloseFile(&pFile)); |
1331 | 0 | return inactiveFile; |
1332 | 0 | } |
1333 | | |
1334 | 0 | int32_t taosGetSysMemory(int64_t *usedKB, int64_t *freeKB, int64_t *cacheBufferKB) { |
1335 | 0 | OS_PARAM_CHECK(usedKB); |
1336 | 0 | OS_PARAM_CHECK(freeKB); |
1337 | 0 | OS_PARAM_CHECK(cacheBufferKB); |
1338 | | #ifdef WINDOWS |
1339 | | MEMORYSTATUSEX memsStat; |
1340 | | memsStat.dwLength = sizeof(memsStat); |
1341 | | if (!GlobalMemoryStatusEx(&memsStat)) { |
1342 | | return TAOS_SYSTEM_WINAPI_ERROR(GetLastError()); |
1343 | | } |
1344 | | |
1345 | | int64_t nMemFree = memsStat.ullAvailPhys / 1024; |
1346 | | int64_t nMemTotal = memsStat.ullTotalPhys / 1024.0; |
1347 | | |
1348 | | *usedKB = nMemTotal - nMemFree; |
1349 | | *freeKB = nMemFree; |
1350 | | *cacheBufferKB = 0; |
1351 | | return 0; |
1352 | | #elif defined(_TD_DARWIN_64) || defined(TD_ASTRA) // TD_ASTRA_TODO |
1353 | | *usedKB = 0; |
1354 | | *freeKB = 0; |
1355 | | *cacheBufferKB = 0; |
1356 | | return 0; |
1357 | | #else |
1358 | | // Try cgroup-aware memory stats first |
1359 | 0 | int32_t cgroupVer = taosDetectCgroupVersion(); |
1360 | 0 | int64_t cgroupLimit = 0; |
1361 | 0 | int64_t cgroupCurrent = 0; |
1362 | |
|
1363 | 0 | if (cgroupVer == 2) { |
1364 | 0 | if (taosReadCgroupInt64(tsCgroupV2MemMaxFile, &cgroupLimit) == 0 && |
1365 | 0 | taosReadCgroupInt64(tsCgroupV2MemCurFile, &cgroupCurrent) == 0 && |
1366 | 0 | cgroupLimit > 0 && cgroupLimit < INT64_MAX) { |
1367 | 0 | int64_t cache = taosGetCgroupMemCache(tsCgroupV2MemStatFile); |
1368 | 0 | *cacheBufferKB = cache / 1024; |
1369 | 0 | *usedKB = (cgroupCurrent > cache) ? (cgroupCurrent - cache) / 1024 : 0; |
1370 | 0 | *freeKB = (cgroupLimit > cgroupCurrent) ? (cgroupLimit - cgroupCurrent) / 1024 : 0; |
1371 | 0 | return 0; |
1372 | 0 | } |
1373 | 0 | } else if (cgroupVer == 1) { |
1374 | | // v1 uses a huge sentinel (near INT64_MAX) for "no limit"; also compare against physical memory |
1375 | 0 | int64_t physMemBytes = (int64_t)sysconf(_SC_PHYS_PAGES) * sysconf(_SC_PAGESIZE); |
1376 | 0 | if (taosReadCgroupInt64(tsCgroupV1MemLimitFile, &cgroupLimit) == 0 && |
1377 | 0 | taosReadCgroupInt64(tsCgroupV1MemUsageFile, &cgroupCurrent) == 0 && |
1378 | 0 | cgroupLimit > 0 && cgroupLimit < INT64_MAX && cgroupLimit < physMemBytes) { |
1379 | 0 | int64_t cache = taosGetCgroupMemCache(tsCgroupV1MemStatFile); |
1380 | 0 | *cacheBufferKB = cache / 1024; |
1381 | 0 | *usedKB = (cgroupCurrent > cache) ? (cgroupCurrent - cache) / 1024 : 0; |
1382 | 0 | *freeKB = (cgroupLimit > cgroupCurrent) ? (cgroupLimit - cgroupCurrent) / 1024 : 0; |
1383 | 0 | return 0; |
1384 | 0 | } |
1385 | 0 | } |
1386 | | |
1387 | | // Fallback to /proc/meminfo |
1388 | 0 | TdFilePtr pFile = taosOpenFile("/proc/meminfo", TD_FILE_READ | TD_FILE_STREAM); |
1389 | 0 | if (pFile == NULL) { |
1390 | 0 | return terrno; |
1391 | 0 | } |
1392 | | |
1393 | 0 | char line[1024] = {0}; |
1394 | 0 | char key[1024] = {0}; |
1395 | 0 | int64_t value = 0; |
1396 | 0 | ssize_t bytes = 0; |
1397 | | |
1398 | | //MemTotal |
1399 | 0 | int64_t total = 0; |
1400 | | |
1401 | | //MemFree |
1402 | 0 | int64_t mfree = 0; |
1403 | | |
1404 | | //MemAvailable |
1405 | 0 | int64_t available = 0; |
1406 | | |
1407 | | //Buffers |
1408 | 0 | int64_t buffer = 0; |
1409 | | |
1410 | | //Cached |
1411 | 0 | int64_t cached = 0; |
1412 | | |
1413 | | //SwapCached ,Active, Inactive, Active(anon), Inactive(anon), Active(file), Inactive(file), Unevictable, Mlocked, SwapTotal |
1414 | | |
1415 | | //SwapFree |
1416 | 0 | int64_t swapFree = 0; |
1417 | | |
1418 | | //Dirty, Writeback, AnonPages, Mapped, Shmem, KReclaimable, Slab |
1419 | | |
1420 | | //SReclaimable |
1421 | 0 | int64_t sReclaimable = 0; |
1422 | |
|
1423 | 0 | for(int32_t i=0; i < 30; i++){ |
1424 | 0 | bytes = taosGetsFile(pFile, sizeof(line), line); |
1425 | 0 | if (bytes < 0) { |
1426 | 0 | TAOS_SKIP_ERROR(taosCloseFile(&pFile)); |
1427 | 0 | return terrno; |
1428 | 0 | } |
1429 | 0 | if (line[0] != 'M' && line[0] != 'B' && line[0] != 'C' && line[0] != 'S') { |
1430 | 0 | line[0] = 0; |
1431 | 0 | continue; |
1432 | 0 | } |
1433 | 0 | taosGetMemValue(line, key, &value); |
1434 | 0 | if(strncmp(key, "MemTotal", 1024) == 0) {total = value; continue;} |
1435 | 0 | if(strncmp(key, "MemFree", 1024) == 0) {mfree = value; continue;} |
1436 | 0 | if(strncmp(key, "MemAvailable", 1024) == 0) {available = value; continue;} |
1437 | 0 | if(strncmp(key, "Buffers", 1024) == 0) {buffer = value; continue;} |
1438 | 0 | if(strncmp(key, "Cached", 1024) == 0) {cached = value; continue;} |
1439 | 0 | if(strncmp(key, "SwapFree", 1024) == 0) {swapFree = value; continue;} |
1440 | 0 | if(strncmp(key, "SReclaimable", 1024) == 0) {sReclaimable = value; continue;} |
1441 | 0 | } |
1442 | | |
1443 | | //free Unused memory (MemFree and SwapFree in /proc/meminfo) |
1444 | 0 | *freeKB = mfree; |
1445 | | //buffers Memory used by kernel buffers (Buffers in /proc/meminfo) |
1446 | | //cache Memory used by the page cache and slabs (Cached and SReclaimable in /proc/meminfo) |
1447 | 0 | *cacheBufferKB = buffer + cached + sReclaimable; |
1448 | 0 | *usedKB = total - *freeKB - *cacheBufferKB; |
1449 | | |
1450 | 0 | TAOS_SKIP_ERROR(taosCloseFile(&pFile)); |
1451 | 0 | return 0; |
1452 | 0 | #endif |
1453 | 0 | } |
1454 | | |
1455 | 0 | int32_t taosGetDiskSize(char *dataDir, SDiskSize *diskSize) { |
1456 | 0 | OS_PARAM_CHECK(dataDir); |
1457 | 0 | OS_PARAM_CHECK(diskSize); |
1458 | | #if defined(WINDOWS) |
1459 | | unsigned _int64 i64FreeBytesToCaller; |
1460 | | unsigned _int64 i64TotalBytes; |
1461 | | unsigned _int64 i64FreeBytes; |
1462 | | |
1463 | | BOOL fResult = GetDiskFreeSpaceExA(dataDir, (PULARGE_INTEGER)&i64FreeBytesToCaller, (PULARGE_INTEGER)&i64TotalBytes, |
1464 | | (PULARGE_INTEGER)&i64FreeBytes); |
1465 | | if (fResult) { |
1466 | | diskSize->total = (int64_t)(i64TotalBytes); |
1467 | | diskSize->avail = (int64_t)(i64FreeBytesToCaller); |
1468 | | diskSize->used = (int64_t)(i64TotalBytes - i64FreeBytes); |
1469 | | return 0; |
1470 | | } else { |
1471 | | // printf("failed to get disk size, dataDir:%s errno:%s", tsDataDir, strerror(ERRNO)); |
1472 | | terrno = TAOS_SYSTEM_WINAPI_ERROR(GetLastError()); |
1473 | | return terrno; |
1474 | | } |
1475 | | #elif defined(_TD_DARWIN_64) |
1476 | | struct statvfs info; |
1477 | | if (statvfs(dataDir, &info)) { |
1478 | | // printf("failed to get disk size, dataDir:%s errno:%s", tsDataDir, strerror(ERRNO)); |
1479 | | terrno = TAOS_SYSTEM_ERROR(ERRNO); |
1480 | | return terrno; |
1481 | | } else { |
1482 | | diskSize->total = info.f_blocks * info.f_frsize; |
1483 | | diskSize->avail = info.f_bavail * info.f_frsize; |
1484 | | diskSize->used = (info.f_blocks - info.f_bfree) * info.f_frsize; |
1485 | | return 0; |
1486 | | } |
1487 | | #elif defined(TD_ASTRA) // TD_ASTRA_TODO |
1488 | | // if (-1 == ioctl(dataDir, FIOFSTATVFSGETBYNAME, &info)) { // TODO:try to check whether the API is available |
1489 | | // terrno = TAOS_SYSTEM_ERROR(ERRNO); |
1490 | | // return terrno; |
1491 | | diskSize->total = 100LL * 1024 * 1024 * 1024; |
1492 | | diskSize->avail = 50LL * 1024 * 1024 * 1024; |
1493 | | diskSize->used = 50LL * 1024 * 1024 * 1024; |
1494 | | // } else { |
1495 | | // diskSize->total = info.f_blocks * info.f_frsize; |
1496 | | // diskSize->avail = info.f_bavail * info.f_frsize; |
1497 | | // diskSize->used = diskSize->total - diskSize->avail; |
1498 | | // } |
1499 | | return 0; |
1500 | | #else |
1501 | 0 | struct statvfs info; |
1502 | 0 | if (-1 == statvfs(dataDir, &info)) { |
1503 | 0 | terrno = TAOS_SYSTEM_ERROR(ERRNO); |
1504 | 0 | return terrno; |
1505 | 0 | } else { |
1506 | 0 | diskSize->total = info.f_blocks * info.f_frsize; |
1507 | 0 | diskSize->avail = info.f_bavail * info.f_frsize; |
1508 | 0 | diskSize->used = diskSize->total - diskSize->avail; |
1509 | | |
1510 | 0 | return 0; |
1511 | 0 | } |
1512 | 0 | #endif |
1513 | 0 | } |
1514 | | |
1515 | 0 | int32_t taosGetProcIO(int64_t *rchars, int64_t *wchars, int64_t *read_bytes, int64_t *write_bytes) { |
1516 | 0 | OS_PARAM_CHECK(rchars); |
1517 | 0 | OS_PARAM_CHECK(wchars); |
1518 | 0 | OS_PARAM_CHECK(read_bytes); |
1519 | 0 | OS_PARAM_CHECK(write_bytes); |
1520 | | #ifdef WINDOWS |
1521 | | IO_COUNTERS io_counter; |
1522 | | if (GetProcessIoCounters(GetCurrentProcess(), &io_counter)) { |
1523 | | *rchars = io_counter.ReadTransferCount; |
1524 | | *wchars = io_counter.WriteTransferCount; |
1525 | | *read_bytes = 0; |
1526 | | *write_bytes = 0; |
1527 | | return 0; |
1528 | | } |
1529 | | return TAOS_SYSTEM_WINAPI_ERROR(GetLastError()); |
1530 | | #elif defined(_TD_DARWIN_64) || defined(TD_ASTRA) |
1531 | | *rchars = 0; |
1532 | | *wchars = 0; |
1533 | | *read_bytes = 0; |
1534 | | *write_bytes = 0; |
1535 | | return 0; |
1536 | | #else |
1537 | 0 | TdFilePtr pFile = taosOpenFile(tsProcIOFile, TD_FILE_READ | TD_FILE_STREAM); |
1538 | 0 | if (pFile == NULL) { |
1539 | 0 | return terrno; |
1540 | 0 | } |
1541 | | |
1542 | 0 | ssize_t bytes = 0; |
1543 | 0 | char line[1024] = {0}; |
1544 | 0 | char tmp[24]; |
1545 | 0 | int readIndex = 0; |
1546 | |
|
1547 | 0 | while (!taosEOFFile(pFile)) { |
1548 | 0 | bytes = taosGetsFile(pFile, sizeof(line), line); |
1549 | 0 | if (bytes < 10) { |
1550 | 0 | break; |
1551 | 0 | } |
1552 | 0 | if (strstr(line, "rchar:") != NULL) { |
1553 | 0 | (void)sscanf(line, "%s %" PRId64, tmp, rchars); |
1554 | 0 | readIndex++; |
1555 | 0 | } else if (strstr(line, "wchar:") != NULL) { |
1556 | 0 | (void)sscanf(line, "%s %" PRId64, tmp, wchars); |
1557 | 0 | readIndex++; |
1558 | 0 | } else if (strstr(line, "read_bytes:") != NULL) { // read_bytes |
1559 | 0 | (void)sscanf(line, "%s %" PRId64, tmp, read_bytes); |
1560 | 0 | readIndex++; |
1561 | 0 | } else if (strstr(line, "write_bytes:") != NULL) { // write_bytes |
1562 | 0 | (void)sscanf(line, "%s %" PRId64, tmp, write_bytes); |
1563 | 0 | readIndex++; |
1564 | 0 | } else { |
1565 | 0 | } |
1566 | |
|
1567 | 0 | if (readIndex >= 4) break; |
1568 | 0 | } |
1569 | |
|
1570 | 0 | TAOS_SKIP_ERROR(taosCloseFile(&pFile)); |
1571 | |
|
1572 | 0 | if (readIndex < 4) { |
1573 | 0 | return -1; |
1574 | 0 | } |
1575 | | |
1576 | 0 | return 0; |
1577 | 0 | #endif |
1578 | 0 | } |
1579 | | |
1580 | 0 | int32_t taosGetProcIODelta(int64_t *rchars, int64_t *wchars, int64_t *read_bytes, int64_t *write_bytes) { |
1581 | 0 | if (rchars == NULL || wchars == NULL || read_bytes == NULL || write_bytes == NULL) { |
1582 | 0 | return TSDB_CODE_INVALID_PARA; |
1583 | 0 | } |
1584 | 0 | static int64_t last_rchars = -1; |
1585 | 0 | static int64_t last_wchars = -1; |
1586 | 0 | static int64_t last_read_bytes = -1; |
1587 | 0 | static int64_t last_write_bytes = -1; |
1588 | 0 | static int64_t cur_rchars = 0; |
1589 | 0 | static int64_t cur_wchars = 0; |
1590 | 0 | static int64_t cur_read_bytes = 0; |
1591 | 0 | static int64_t cur_write_bytes = 0; |
1592 | 0 | int32_t code = taosGetProcIO(&cur_rchars, &cur_wchars, &cur_read_bytes, &cur_write_bytes); |
1593 | 0 | if (code == 0) { |
1594 | 0 | if(last_rchars >=0 && last_wchars >=0 && last_read_bytes >=0 && last_write_bytes >= 0){ |
1595 | 0 | *rchars = cur_rchars - last_rchars; |
1596 | 0 | *wchars = cur_wchars - last_wchars; |
1597 | 0 | *read_bytes = cur_read_bytes - last_read_bytes; |
1598 | 0 | *write_bytes = cur_write_bytes - last_write_bytes; |
1599 | 0 | } |
1600 | 0 | else{ |
1601 | 0 | *rchars = 0; |
1602 | 0 | *wchars = 0; |
1603 | 0 | *read_bytes = 0; |
1604 | 0 | *write_bytes = 0; |
1605 | 0 | } |
1606 | 0 | last_rchars = cur_rchars; |
1607 | 0 | last_wchars = cur_wchars; |
1608 | 0 | last_read_bytes = cur_read_bytes; |
1609 | 0 | last_write_bytes = cur_write_bytes; |
1610 | 0 | } else { |
1611 | 0 | return code; |
1612 | 0 | } |
1613 | 0 | return 0; |
1614 | 0 | } |
1615 | 0 | void taosSetDefaultProcIODelta(int64_t *rchars, int64_t *wchars, int64_t *read_bytes, int64_t *write_bytes) { |
1616 | 0 | if(rchars) *rchars = 0; |
1617 | 0 | if(wchars) *wchars = 0; |
1618 | 0 | if(read_bytes) *read_bytes = 0; |
1619 | 0 | if(write_bytes) *write_bytes = 0; |
1620 | 0 | } |
1621 | | |
1622 | 0 | int32_t taosGetCardInfo(int64_t *receive_bytes, int64_t *transmit_bytes) { |
1623 | 0 | OS_PARAM_CHECK(receive_bytes); |
1624 | 0 | OS_PARAM_CHECK(transmit_bytes); |
1625 | 0 | *receive_bytes = 0; |
1626 | 0 | *transmit_bytes = 0; |
1627 | |
|
1628 | | #ifdef WINDOWS |
1629 | | return 0; |
1630 | | #elif defined(_TD_DARWIN_64) || defined(TD_ASTRA) |
1631 | | return 0; |
1632 | | #else |
1633 | 0 | TdFilePtr pFile = taosOpenFile(tsSysNetFile, TD_FILE_READ | TD_FILE_STREAM); |
1634 | 0 | if (pFile == NULL) { |
1635 | 0 | return terrno; |
1636 | 0 | } |
1637 | | |
1638 | 0 | ssize_t _bytes = 0; |
1639 | 0 | char line[1024]; |
1640 | |
|
1641 | 0 | while (!taosEOFFile(pFile)) { |
1642 | 0 | int64_t o_rbytes = 0; |
1643 | 0 | int64_t rpackts = 0; |
1644 | 0 | int64_t o_tbytes = 0; |
1645 | 0 | int64_t tpackets = 0; |
1646 | 0 | int64_t nouse1 = 0; |
1647 | 0 | int64_t nouse2 = 0; |
1648 | 0 | int64_t nouse3 = 0; |
1649 | 0 | int64_t nouse4 = 0; |
1650 | 0 | int64_t nouse5 = 0; |
1651 | 0 | int64_t nouse6 = 0; |
1652 | 0 | char nouse0[200] = {0}; |
1653 | |
|
1654 | 0 | _bytes = taosGetsFile(pFile, sizeof(line), line); |
1655 | 0 | if (_bytes <= 0) { |
1656 | 0 | break; |
1657 | 0 | } |
1658 | | |
1659 | 0 | line[_bytes - 1] = 0; |
1660 | |
|
1661 | 0 | if (strstr(line, "lo:") != NULL) { |
1662 | 0 | continue; |
1663 | 0 | } |
1664 | | |
1665 | 0 | (void)sscanf(line, |
1666 | 0 | "%s %" PRId64 " %" PRId64 " %" PRId64 " %" PRId64 " %" PRId64 " %" PRId64 " %" PRId64 " %" PRId64 " %" PRId64 |
1667 | 0 | " %" PRId64, |
1668 | 0 | nouse0, &o_rbytes, &rpackts, &nouse1, &nouse2, &nouse3, &nouse4, &nouse5, &nouse6, &o_tbytes, &tpackets); |
1669 | 0 | *receive_bytes += o_rbytes; |
1670 | 0 | *transmit_bytes += o_tbytes; |
1671 | 0 | } |
1672 | |
|
1673 | 0 | TAOS_SKIP_ERROR(taosCloseFile(&pFile)); |
1674 | |
|
1675 | 0 | return 0; |
1676 | 0 | #endif |
1677 | 0 | } |
1678 | | |
1679 | 0 | int32_t taosGetCardInfoDelta(int64_t *receive_bytes, int64_t *transmit_bytes) { |
1680 | 0 | OS_PARAM_CHECK(receive_bytes); |
1681 | 0 | OS_PARAM_CHECK(transmit_bytes); |
1682 | 0 | static int64_t last_receive_bytes = -1; |
1683 | 0 | static int64_t last_transmit_bytes = -1; |
1684 | 0 | int64_t cur_receive_bytes = 0; |
1685 | 0 | int64_t cur_transmit_bytes = 0; |
1686 | 0 | int32_t code = taosGetCardInfo(&cur_receive_bytes, &cur_transmit_bytes); |
1687 | 0 | if (code == 0) { |
1688 | 0 | if(last_receive_bytes >= 0 && last_transmit_bytes >= 0){ |
1689 | 0 | *receive_bytes = cur_receive_bytes - last_receive_bytes; |
1690 | 0 | *transmit_bytes = cur_transmit_bytes - last_transmit_bytes; |
1691 | 0 | } |
1692 | 0 | else{ |
1693 | 0 | *receive_bytes = 0; |
1694 | 0 | *transmit_bytes = 0; |
1695 | 0 | } |
1696 | |
|
1697 | 0 | last_receive_bytes = cur_receive_bytes; |
1698 | 0 | last_transmit_bytes = cur_transmit_bytes; |
1699 | 0 | } else { |
1700 | 0 | return code; |
1701 | 0 | } |
1702 | 0 | return 0; |
1703 | 0 | } |
1704 | 0 | void taosSetDefaultCardInfoDelta(int64_t *receive_bytes, int64_t *transmit_bytes) { |
1705 | 0 | if (receive_bytes) *receive_bytes = 0; |
1706 | 0 | if (transmit_bytes) *transmit_bytes = 0; |
1707 | 0 | } |
1708 | | |
1709 | | #if 0 |
1710 | | void taosKillSystem() { |
1711 | | #ifdef WINDOWS |
1712 | | printf("function taosKillSystem, exit!"); |
1713 | | exit(0); |
1714 | | #elif defined(_TD_DARWIN_64) || defined(TD_ASTRA) |
1715 | | printf("function taosKillSystem, exit!"); |
1716 | | exit(0); |
1717 | | #else |
1718 | | // SIGINT |
1719 | | (void)printf("%sd will shut down soon", CUS_PROMPT); |
1720 | | (void)kill(tsProcId, 2); |
1721 | | #endif |
1722 | | } |
1723 | | #endif |
1724 | | |
1725 | 0 | #define UUIDLEN (36) |
1726 | 0 | int32_t taosGetSystemUUIDLimit36(char *uid, int32_t uidlen) { |
1727 | 0 | OS_PARAM_CHECK(uid); |
1728 | | #ifdef WINDOWS |
1729 | | GUID guid; |
1730 | | HRESULT h = CoCreateGuid(&guid); |
1731 | | if (h != S_OK) { |
1732 | | return TAOS_SYSTEM_WINAPI_ERROR(GetLastError()); |
1733 | | } |
1734 | | (void)snprintf(uid, uidlen, "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", guid.Data1, guid.Data2, guid.Data3, |
1735 | | guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3], guid.Data4[4], guid.Data4[5], guid.Data4[6], |
1736 | | guid.Data4[7]); |
1737 | | |
1738 | | return 0; |
1739 | | #elif defined(_TD_DARWIN_64) |
1740 | | uuid_t uuid = {0}; |
1741 | | char buf[UUIDLEN37]; |
1742 | | memset(buf, 0, UUIDLEN37); |
1743 | | uuid_generate(uuid); |
1744 | | // it's caller's responsibility to make enough space for `uid`, that's 36-char + 1-null |
1745 | | uuid_unparse_lower(uuid, buf); |
1746 | | (void)snprintf(uid, uidlen, "%.*s", (int)sizeof(buf), buf); |
1747 | | return 0; |
1748 | | #elif defined(TD_ASTRA) |
1749 | | const char *template = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx"; |
1750 | | const char *hex_chars = "0123456789abcdef"; |
1751 | | int32_t len = uidlen > 36 ? 36 : uidlen; |
1752 | | |
1753 | | for (int32_t i = 0; i < len; i++) { |
1754 | | if (template[i] == 'x') { |
1755 | | uid[i] = hex_chars[taosRand() & 15]; |
1756 | | } else if (template[i] == 'y') { |
1757 | | uid[i] = hex_chars[(taosRand() & 3) + 8]; // 8, 9, a, or b |
1758 | | } else { |
1759 | | uid[i] = template[i]; |
1760 | | } |
1761 | | } |
1762 | | if (len >= 0) { |
1763 | | uid[len] = 0; |
1764 | | } |
1765 | | |
1766 | | return 0; |
1767 | | #else |
1768 | 0 | int64_t len = 0; |
1769 | | |
1770 | | // fd = open("/proc/sys/kernel/random/uuid", 0); |
1771 | 0 | TdFilePtr pFile = taosOpenFile("/proc/sys/kernel/random/uuid", TD_FILE_READ); |
1772 | 0 | if (pFile == NULL) { |
1773 | 0 | return terrno; |
1774 | 0 | } else { |
1775 | 0 | len = taosReadFile(pFile, uid, uidlen); |
1776 | 0 | TAOS_SKIP_ERROR(taosCloseFile(&pFile)); |
1777 | 0 | if (len < 0) { |
1778 | 0 | return terrno; |
1779 | 0 | } |
1780 | 0 | } |
1781 | 0 | if (len >= UUIDLEN + 1) { |
1782 | 0 | uid[len - 1] = 0; |
1783 | 0 | } else { |
1784 | 0 | uid[uidlen - 1] = 0; |
1785 | 0 | } |
1786 | |
|
1787 | 0 | return 0; |
1788 | 0 | #endif |
1789 | 0 | } |
1790 | | |
1791 | 0 | int32_t taosGetSystemUUIDLen(char *uid, int32_t uidlen) { |
1792 | 0 | if (uid == NULL || uidlen <= 0) { |
1793 | 0 | return TSDB_CODE_APP_ERROR; |
1794 | 0 | } |
1795 | 0 | int num = (uidlen % UUIDLEN == 0) ? (uidlen / UUIDLEN) : (uidlen / UUIDLEN + 1); |
1796 | 0 | int left = uidlen; |
1797 | 0 | for (int i = 0; i < num; ++i) { |
1798 | 0 | int32_t code = taosGetSystemUUIDLimit36(uid + i * UUIDLEN, left); |
1799 | 0 | if (code != 0) { |
1800 | 0 | return code; |
1801 | 0 | } |
1802 | 0 | left -= UUIDLEN; |
1803 | 0 | } |
1804 | 0 | return TSDB_CODE_SUCCESS; |
1805 | 0 | } |
1806 | | |
1807 | 0 | char *taosGetCmdlineByPID(int pid) { |
1808 | | #ifdef WINDOWS |
1809 | | return ""; |
1810 | | #elif defined(_TD_DARWIN_64) |
1811 | | static char cmdline[1024]; |
1812 | | SET_ERRNO(0); |
1813 | | |
1814 | | if (proc_pidpath(pid, cmdline, sizeof(cmdline)) <= 0) { |
1815 | | fprintf(stderr, "PID is %d, %s", pid, strerror(ERRNO)); |
1816 | | return strerror(ERRNO); |
1817 | | } |
1818 | | |
1819 | | return cmdline; |
1820 | | #elif defined(TD_ASTRA) |
1821 | | return ""; |
1822 | | #else |
1823 | 0 | static char cmdline[1024]; |
1824 | 0 | (void)snprintf(cmdline, sizeof(cmdline), "/proc/%d/cmdline", pid); |
1825 | | |
1826 | | // int fd = open(cmdline, O_RDONLY); |
1827 | 0 | TdFilePtr pFile = taosOpenFile(cmdline, TD_FILE_READ); |
1828 | 0 | if (pFile != NULL) { |
1829 | 0 | int n = taosReadFile(pFile, cmdline, sizeof(cmdline) - 1); |
1830 | 0 | if (n < 0) n = 0; |
1831 | |
|
1832 | 0 | if (n > 0 && cmdline[n - 1] == '\n') --n; |
1833 | |
|
1834 | 0 | cmdline[n] = 0; |
1835 | |
|
1836 | 0 | TAOS_SKIP_ERROR(taosCloseFile(&pFile)); |
1837 | 0 | } else { |
1838 | 0 | cmdline[0] = 0; |
1839 | 0 | } |
1840 | |
|
1841 | 0 | return cmdline; |
1842 | 0 | #endif |
1843 | 0 | } |
1844 | | |
1845 | 0 | int64_t taosGetOsUptime() { |
1846 | | #ifdef WINDOWS |
1847 | | #elif defined(_TD_DARWIN_64) || defined(TD_ASTRA) |
1848 | | #else |
1849 | 0 | struct sysinfo info; |
1850 | 0 | if (-1 == sysinfo(&info)) { |
1851 | 0 | terrno = TAOS_SYSTEM_ERROR(ERRNO); |
1852 | 0 | return terrno; |
1853 | 0 | } |
1854 | | |
1855 | 0 | return (int64_t)info.uptime * 1000; |
1856 | | |
1857 | 0 | #endif |
1858 | 0 | return 0; |
1859 | 0 | } |
1860 | | |
1861 | 0 | void taosSetCoreDump(bool enable) { |
1862 | 0 | if (!enable) return; |
1863 | | #ifdef WINDOWS |
1864 | | /* Register vectored exception handler FIRST - it runs before SEH and can |
1865 | | * catch heap corruption (STATUS_HEAP_CORRUPTION 0xC0000374) which may |
1866 | | * bypass SetUnhandledExceptionFilter in some cases. */ |
1867 | | AddVectoredExceptionHandler(1, FlVectoredExceptionHandler); |
1868 | | |
1869 | | /* Also set the unhandled exception filter for normal crashes */ |
1870 | | SetUnhandledExceptionFilter(&FlCrashDump); |
1871 | | |
1872 | | /* Register CRT handlers for various runtime errors */ |
1873 | | _set_invalid_parameter_handler(FlInvalidParameterHandler); |
1874 | | _set_purecall_handler(FlPureCallHandler); |
1875 | | |
1876 | | /* Handle abort() calls */ |
1877 | | signal(SIGABRT, FlAbortHandler); |
1878 | | |
1879 | | #elif defined(_TD_DARWIN_64) || defined(TD_ASTRA) |
1880 | | #else |
1881 | | // 1. set ulimit -c unlimited |
1882 | 0 | struct rlimit rlim; |
1883 | 0 | struct rlimit rlim_new; |
1884 | 0 | if (getrlimit(RLIMIT_CORE, &rlim) == 0) { |
1885 | 0 | #ifndef _ALPINE |
1886 | | // printf("the old unlimited para: rlim_cur=%" PRIu64 ", rlim_max=%" PRIu64, rlim.rlim_cur, rlim.rlim_max); |
1887 | | #else |
1888 | | // printf("the old unlimited para: rlim_cur=%llu, rlim_max=%llu", rlim.rlim_cur, rlim.rlim_max); |
1889 | | #endif |
1890 | 0 | rlim_new.rlim_cur = RLIM_INFINITY; |
1891 | 0 | rlim_new.rlim_max = RLIM_INFINITY; |
1892 | 0 | if (setrlimit(RLIMIT_CORE, &rlim_new) != 0) { |
1893 | | // printf("set unlimited fail, error: %s", strerror(ERRNO)); |
1894 | 0 | rlim_new.rlim_cur = rlim.rlim_max; |
1895 | 0 | rlim_new.rlim_max = rlim.rlim_max; |
1896 | 0 | (void)setrlimit(RLIMIT_CORE, &rlim_new); |
1897 | 0 | } |
1898 | 0 | } |
1899 | |
|
1900 | 0 | if (getrlimit(RLIMIT_CORE, &rlim) == 0) { |
1901 | 0 | #ifndef _ALPINE |
1902 | | // printf("the new unlimited para: rlim_cur=%" PRIu64 ", rlim_max=%" PRIu64, rlim.rlim_cur, rlim.rlim_max); |
1903 | | #else |
1904 | | // printf("the new unlimited para: rlim_cur=%llu, rlim_max=%llu", rlim.rlim_cur, rlim.rlim_max); |
1905 | | #endif |
1906 | 0 | } |
1907 | |
|
1908 | 0 | #ifndef _TD_ARM_ |
1909 | | // 2. set the path for saving core file |
1910 | 0 | struct __sysctl_args args; |
1911 | |
|
1912 | 0 | int old_usespid = 0; |
1913 | 0 | size_t old_len = 0; |
1914 | 0 | int new_usespid = 1; |
1915 | 0 | size_t new_len = sizeof(new_usespid); |
1916 | |
|
1917 | 0 | int name[] = {CTL_KERN, KERN_CORE_USES_PID}; |
1918 | |
|
1919 | 0 | (void)memset(&args, 0, sizeof(struct __sysctl_args)); |
1920 | 0 | args.name = name; |
1921 | 0 | args.nlen = sizeof(name) / sizeof(name[0]); |
1922 | 0 | args.oldval = &old_usespid; |
1923 | 0 | args.oldlenp = &old_len; |
1924 | 0 | args.newval = &new_usespid; |
1925 | 0 | args.newlen = new_len; |
1926 | |
|
1927 | 0 | old_len = sizeof(old_usespid); |
1928 | |
|
1929 | 0 | #ifndef __loongarch64 |
1930 | 0 | if (syscall(SYS__sysctl, &args) == -1) { |
1931 | | // printf("_sysctl(kern_core_uses_pid) set fail: %s", strerror(ERRNO)); |
1932 | 0 | } |
1933 | 0 | #endif |
1934 | | |
1935 | | // printf("The old core_uses_pid[%" PRIu64 "]: %d", old_len, old_usespid); |
1936 | |
|
1937 | 0 | old_usespid = 0; |
1938 | 0 | old_len = 0; |
1939 | 0 | (void)memset(&args, 0, sizeof(struct __sysctl_args)); |
1940 | 0 | args.name = name; |
1941 | 0 | args.nlen = sizeof(name) / sizeof(name[0]); |
1942 | 0 | args.oldval = &old_usespid; |
1943 | 0 | args.oldlenp = &old_len; |
1944 | |
|
1945 | 0 | old_len = sizeof(old_usespid); |
1946 | |
|
1947 | 0 | #ifndef __loongarch64 |
1948 | 0 | if (syscall(SYS__sysctl, &args) == -1) { |
1949 | | // printf("_sysctl(kern_core_uses_pid) get fail: %s", strerror(ERRNO)); |
1950 | 0 | } |
1951 | 0 | #endif |
1952 | | |
1953 | | // printf("The new core_uses_pid[%" PRIu64 "]: %d", old_len, old_usespid); |
1954 | 0 | #endif |
1955 | 0 | #endif |
1956 | 0 | } |
1957 | | |
1958 | 0 | SysNameInfo taosGetSysNameInfo() { |
1959 | | #ifdef WINDOWS |
1960 | | SysNameInfo info = {0}; |
1961 | | DWORD dwVersion = GetVersion(); |
1962 | | |
1963 | | char *tmp = NULL; |
1964 | | tmp = getenv("OS"); |
1965 | | if (tmp != NULL) tstrncpy(info.sysname, tmp, sizeof(info.sysname)); |
1966 | | tmp = getenv("COMPUTERNAME"); |
1967 | | if (tmp != NULL) tstrncpy(info.nodename, tmp, sizeof(info.nodename)); |
1968 | | sprintf_s(info.release, sizeof(info.release), "%d", dwVersion & 0x0F); |
1969 | | sprintf_s(info.version, sizeof(info.release), "%d", (dwVersion >> 8) & 0x0F); |
1970 | | tmp = getenv("PROCESSOR_ARCHITECTURE"); |
1971 | | if (tmp != NULL) tstrncpy(info.machine, tmp, sizeof(info.machine)); |
1972 | | |
1973 | | return info; |
1974 | | #elif defined(_TD_DARWIN_64) |
1975 | | SysNameInfo info = {0}; |
1976 | | |
1977 | | struct utsname uts; |
1978 | | if (!uname(&uts)) { |
1979 | | tstrncpy(info.sysname, uts.sysname, sizeof(info.sysname)); |
1980 | | tstrncpy(info.nodename, uts.nodename, sizeof(info.nodename)); |
1981 | | tstrncpy(info.release, uts.release, sizeof(info.release)); |
1982 | | tstrncpy(info.version, uts.version, sizeof(info.version)); |
1983 | | tstrncpy(info.machine, uts.machine, sizeof(info.machine)); |
1984 | | } |
1985 | | |
1986 | | char localHostName[512]; |
1987 | | TAOS_SKIP_ERROR(taosGetlocalhostname(localHostName, 512)); |
1988 | | TdCmdPtr pCmd = taosOpenCmd("scutil --get LocalHostName"); |
1989 | | tstrncpy(info.nodename, localHostName, sizeof(info.nodename)); |
1990 | | |
1991 | | return info; |
1992 | | #else |
1993 | 0 | SysNameInfo info = {0}; |
1994 | 0 | struct utsname uts; |
1995 | 0 | if (!uname(&uts)) { |
1996 | 0 | tstrncpy(info.sysname, uts.sysname, sizeof(info.sysname)); |
1997 | 0 | tstrncpy(info.nodename, uts.nodename, sizeof(info.nodename)); |
1998 | 0 | tstrncpy(info.release, uts.release, sizeof(info.release)); |
1999 | 0 | tstrncpy(info.version, uts.version, sizeof(info.version)); |
2000 | 0 | tstrncpy(info.machine, uts.machine, sizeof(info.machine)); |
2001 | 0 | } else { |
2002 | 0 | terrno = TAOS_SYSTEM_ERROR(ERRNO); |
2003 | 0 | } |
2004 | |
|
2005 | 0 | return info; |
2006 | 0 | #endif |
2007 | 0 | } |
2008 | | |
2009 | 0 | bool taosCheckCurrentInDll() { |
2010 | | #ifdef WINDOWS |
2011 | | MEMORY_BASIC_INFORMATION mbi; |
2012 | | char path[PATH_MAX] = {0}; |
2013 | | GetModuleFileName( |
2014 | | ((VirtualQuery(taosCheckCurrentInDll, &mbi, sizeof(mbi)) != 0) ? (HMODULE)mbi.AllocationBase : NULL), path, |
2015 | | PATH_MAX); |
2016 | | int strLastIndex = strlen(path); |
2017 | | if ((path[strLastIndex - 3] == 'd' || path[strLastIndex - 3] == 'D') && |
2018 | | (path[strLastIndex - 2] == 'l' || path[strLastIndex - 2] == 'L') && |
2019 | | (path[strLastIndex - 1] == 'l' || path[strLastIndex - 1] == 'L')) { |
2020 | | return true; |
2021 | | } |
2022 | | return false; |
2023 | | #else |
2024 | 0 | return false; |
2025 | 0 | #endif |
2026 | 0 | } |
2027 | | |
2028 | | #ifdef _TD_DARWIN_64 |
2029 | | int32_t taosGetMaclocalhostnameByCommand(char *hostname, size_t maxLen) { |
2030 | | TdCmdPtr pCmd = taosOpenCmd("scutil --get LocalHostName"); |
2031 | | if (pCmd != NULL) { |
2032 | | if (taosGetsCmd(pCmd, maxLen - 1, hostname) > 0) { |
2033 | | int len = strlen(hostname); |
2034 | | if (hostname[len - 1] == '\n') { |
2035 | | hostname[len - 1] = '\0'; |
2036 | | } |
2037 | | return 0; |
2038 | | } |
2039 | | taosCloseCmd(&pCmd); |
2040 | | } |
2041 | | return TAOS_SYSTEM_ERROR(ERRNO); |
2042 | | } |
2043 | | |
2044 | | int32_t getMacLocalHostNameBySCD(char *hostname, size_t maxLen) { |
2045 | | SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR(""), NULL, NULL); |
2046 | | CFStringRef hostname_cfstr = SCDynamicStoreCopyLocalHostName(store); |
2047 | | if (hostname_cfstr != NULL) { |
2048 | | CFStringGetCString(hostname_cfstr, hostname, maxLen - 1, kCFStringEncodingMacRoman); |
2049 | | CFRelease(hostname_cfstr); |
2050 | | } else { |
2051 | | return -1; |
2052 | | } |
2053 | | CFRelease(store); |
2054 | | return 0; |
2055 | | } |
2056 | | #endif |
2057 | | |
2058 | 0 | int32_t taosGetlocalhostname(char *hostname, size_t maxLen) { |
2059 | 0 | OS_PARAM_CHECK(hostname); |
2060 | | #ifdef _TD_DARWIN_64 |
2061 | | int res = getMacLocalHostNameBySCD(hostname, maxLen); |
2062 | | if (res != 0) { |
2063 | | return taosGetMaclocalhostnameByCommand(hostname, maxLen); |
2064 | | } else { |
2065 | | return 0; |
2066 | | } |
2067 | | #else |
2068 | 0 | int r = gethostname(hostname, maxLen); |
2069 | 0 | if (-1 == r) { |
2070 | 0 | terrno = TAOS_SYSTEM_ERROR(ERRNO); |
2071 | 0 | return terrno; |
2072 | 0 | } |
2073 | 0 | return r; |
2074 | 0 | #endif |
2075 | 0 | } |