time_md.c
来自「This is a resource based on j2me embedde」· C语言 代码 · 共 367 行
C
367 行
/* * @(#)time_md.c 1.8 06/10/10 * * Copyright 1990-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License version * 2 only, as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 2 for more details (a copy is * included at /legal/license.txt). * * You should have received a copy of the GNU General Public License * version 2 along with this work; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA * * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa * Clara, CA 95054 or visit www.sun.com if you need additional * information or have any questions. * */#include "javavm/include/porting/time.h"#include "javavm/include/porting/threads.h"#include "javavm/include/porting/ansi/stdlib.h"#include "portlibs/posix/threads.h"#include <stdio.h>#include <pthread.h>#include <errno.h>#include <dlfcn.h>#include <unistd.h>#include <string.h>#include "javavm/include/interpreter.h"#include "javavm/include/assert.h"#ifdef CVM_JVMTI#ifndef __UCLIBC__#include <gnu/libc-version.h>#endif#ifndef clockid_ttypedef int clockid_t;#endifstatic int (*_clock_gettime)(clockid_t, struct timespec *);static int (*_clock_getres)(clockid_t, struct timespec *);static int (*_pthread_getcpuclockid)(pthread_t, clockid_t *);static CVMBool supportsFastThreadCpuTime = CVM_FALSE;static CVMBool isNPTL = CVM_FALSE;static int clockTicsPerSec = 100;#define SEC_IN_NANOSECS CONST64(1000000000)void CVMtimeClockInit(void) { /* we do dlopen's in this particular order due to bug in linux */ /* dynamical loader (see 6348968) leading to crash on exit */#ifdef CLOCK_PROCESS_CPUTIME_ID void* handle = dlopen("librt.so.1", RTLD_LAZY); if (handle == NULL) { handle = dlopen("librt.so", RTLD_LAZY); } if (handle) { int (*clock_getres_func)(clockid_t, struct timespec*) = (int(*)(clockid_t, struct timespec*))dlsym(handle, "clock_getres"); int (*clock_gettime_func)(clockid_t, struct timespec*) = (int(*)(clockid_t, struct timespec*))dlsym(handle, "clock_gettime"); if (clock_getres_func && clock_gettime_func) { /* * See if monotonic clock is supported by the kernel. Note that some * early implementations simply return kernel jiffies (updated every * 1/100 or 1/1000 second). It would be bad to use such a low res clock * for nano time (though the monotonic property is still nice to have). * It's fixed in newer kernels, however clock_getres() still returns * 1/HZ. We check if clock_getres() works, but will ignore its reported * resolution for now. Hopefully as people move to new kernels, this * won't be a problem. */ struct timespec res; struct timespec tp; if (clock_getres_func (CLOCK_PROCESS_CPUTIME_ID, &res) == 0 && clock_gettime_func(CLOCK_PROCESS_CPUTIME_ID, &tp) == 0) { /* yes, monotonic clock is supported */ _clock_gettime = clock_gettime_func; _clock_getres = clock_getres_func; } else { /* close librt if there is no monotonic clock */ dlclose(handle); } } } {#ifndef __UCLIBC__ char _gnu_libc_version[32]; char *glibc_version = _gnu_libc_version; char *libpthread_version; /* * Save glibc and pthread version strings. Note that _CS_GNU_LIBC_VERSION * and _CS_GNU_LIBPTHREAD_VERSION are supported in glibc >= 2.3.2. Use a * generic name for earlier versions. * Define macros here so we can build HotSpot on old systems. */# ifndef _CS_GNU_LIBC_VERSION# define _CS_GNU_LIBC_VERSION 2# endif# ifndef _CS_GNU_LIBPTHREAD_VERSION# define _CS_GNU_LIBPTHREAD_VERSION 3# endif size_t n = confstr(_CS_GNU_LIBC_VERSION, NULL, 0); if (n > 0) { char *str = (char *)malloc(n); confstr(_CS_GNU_LIBC_VERSION, str, n); glibc_version = str; } else { /* _CS_GNU_LIBC_VERSION is not supported, try gnu_get_libc_version()*/ snprintf(_gnu_libc_version, sizeof(_gnu_libc_version), "glibc %s %s", glibc_version, gnu_get_libc_release()); } n = confstr(_CS_GNU_LIBPTHREAD_VERSION, NULL, 0); if (n > 0) { char *str = (char *)malloc(n); confstr(_CS_GNU_LIBPTHREAD_VERSION, str, n); /* * Vanilla RH-9 (glibc 2.3.2) has a bug that confstr() always tells * us "NPTL-0.29" even we are running with LinuxThreads. Check if * this is the case: */ if (strcmp(glibc_version, "glibc 2.3.2") == 0 && strstr(str, "NPTL")) { /* * LinuxThreads has a hard limit on max number of threads. So * sysconf(_SC_THREAD_THREADS_MAX) will return a positive * value. On the other hand, NPTL does not have such a limit, * sysconf() will return -1 and errno is not changed. * Check if it is really NPTL: */ if (sysconf(_SC_THREAD_THREADS_MAX) > 0) { free(str); str = "linuxthreads"; } } libpthread_version = str; } else { /* glibc before 2.3.2 only has LinuxThreads. */ libpthread_version = "linuxthreads"; } if (strstr(libpthread_version, "NPTL")) { isNPTL = CVM_TRUE; }#endif /* __UCLIBC__ */ }#endif clockTicsPerSec = sysconf(_SC_CLK_TCK);}void CVMtimeThreadCpuClockInit(CVMThreadID *threadID) { clockid_t clockid; struct timespec tp; int (*pthread_getcpuclockid_func)(pthread_t, clockid_t *) = (int(*)(pthread_t, clockid_t *)) dlsym(RTLD_DEFAULT, "pthread_getcpuclockid"); /* * Switch to using fast clocks for thread cpu time if * the sys_clock_getres() returns 0 error code. * Note, that some kernels may support the current thread * clock (CLOCK_THREAD_CPUTIME_ID) but not the clocks * returned by the pthread_getcpuclockid(). * If the fast Posix clocks are supported then the sys_clock_getres() * must return at least tp.tv_sec == 0 which means a resolution * better than 1 sec. This is extra check for reliability. */ if(pthread_getcpuclockid_func && pthread_getcpuclockid_func(POSIX_COOKIE(threadID), &clockid) == 0 && _clock_getres != NULL && _clock_getres(clockid, &tp) == 0 && tp.tv_sec == 0) { _pthread_getcpuclockid = pthread_getcpuclockid_func; supportsFastThreadCpuTime = CVM_TRUE; }}/* * current_thread_cpu_time(bool) and thread_cpu_time(Thread*, bool) * are used by JVM M&M and JVMTI to get user+sys or user CPU time * of a thread. * * current_thread_cpu_time() and thread_cpu_time(Thread*) returns * the fast estimate available on the platform. * * * -1 on error. */ static CVMInt64threadCpuTimeX(CVMThreadID *thread, CVMBool user_sys_cpu_time) { static CVMBool proc_pid_cpu_avail = CVM_TRUE; static CVMBool proc_task_unchecked = CVM_TRUE; static const char *proc_stat_path = "/proc/%d/stat"; pid_t tid = POSIX_COOKIE(thread); int i; char *s; char stat[2048]; int statlen; char proc_name[64]; int count; long sys_time, user_time; char string[64]; int idummy; long ldummy; FILE *fp; /* We first try accessing /proc/<pid>/cpu since this is faster to * process. If this file is not present (linux kernels 2.5 and above) * then we open /proc/<pid>/stat. */ if ( proc_pid_cpu_avail ) { sprintf(proc_name, "/proc/%d/cpu", tid); fp = fopen(proc_name, "r"); if ( fp != NULL ) { count = fscanf( fp, "%s %lu %lu\n", string, &user_time, &sys_time); fclose(fp); if ( count != 3 ) return -1; if (user_sys_cpu_time) { return ((CVMInt64)sys_time + (CVMInt64)user_time) * (SEC_IN_NANOSECS / clockTicsPerSec); } else { return (CVMInt64)user_time * (SEC_IN_NANOSECS / clockTicsPerSec); } } else proc_pid_cpu_avail = CVM_FALSE; } /* * The /proc/<tid>/stat aggregates per-process usage on * new Linux kernels 2.6+ where NPTL is supported. * The /proc/self/task/<tid>/stat still has the per-thread usage. * See bug 6328462. * There can be no directory /proc/self/task on kernels 2.4 with NPTL * and possibly in some other cases, so we check its availability. */ if (proc_task_unchecked && isNPTL) { /* This is executed only once */ proc_task_unchecked = CVM_FALSE; fp = fopen("/proc/self/task", "r"); if (fp != NULL) { proc_stat_path = "/proc/self/task/%d/stat"; fclose(fp); } } sprintf(proc_name, proc_stat_path, tid); fp = fopen(proc_name, "r"); if ( fp == NULL ) return -1; statlen = fread(stat, 1, 2047, fp); stat[statlen] = '\0'; fclose(fp); /* * Skip pid and the command string. Note that we could be dealing with * weird command names, e.g. user could decide to rename java launcher * to "java 1.4.2 :)", then the stat file would look like * 1234 (java 1.4.2 :)) R ... ... * We don't really need to know the command string, just find the last * occurrence of ")" and then start parsing from there. See bug 4726580. */ s = strrchr(stat, ')'); i = 0; if (s == NULL ) return -1; /* Skip blank chars */ do s++; while (isspace(*s)); count = sscanf(s,"%c %d %d %d %d %d %lu %lu %lu %lu %lu %lu %lu", (char *)&idummy, &idummy, &idummy, &idummy, &idummy, &idummy, &ldummy, &ldummy, &ldummy, &ldummy, &ldummy, &user_time, &sys_time); if ( count != 13 ) return -1; if (user_sys_cpu_time) { return ((jlong)sys_time + (jlong)user_time) * (SEC_IN_NANOSECS / clockTicsPerSec); } else { return (jlong)user_time * (SEC_IN_NANOSECS / clockTicsPerSec); }}/* * This is the fastest way to get thread cpu time on Linux. * Returns cpu time (user+sys) for any thread, not only for current. * POSIX compliant clocks are implemented in the kernels 2.6.16+. * It might work on 2.6.10+ with a special kernel/glibc patch. * For reference, please, see IEEE Std 1003.1-2004: * http://www.unix.org/single_unix_specification */static CVMInt64fastThreadCpuTime(clockid_t clockid) { struct timespec tp; int rc = 0; rc = _clock_gettime(clockid, &tp); CVMassert(rc == 0); return (tp.tv_sec * SEC_IN_NANOSECS) + tp.tv_nsec;}CVMInt64CVMtimeThreadCpuTime(CVMThreadID *thread) { /* consistent with what current_thread_cpu_time() returns */ if (supportsFastThreadCpuTime) { pthread_t tid = POSIX_COOKIE(thread); clockid_t clockid; int rc; /* Get the thread clockid */ rc = _pthread_getcpuclockid(tid, &clockid); CVMassert(rc == 0); return fastThreadCpuTime(clockid); } else { return threadCpuTimeX(thread, CVM_TRUE /* user + sys */); }}CVMBool CVMtimeIsThreadCpuTimeSupported(void) { return CVM_TRUE;}CVMInt64CVMtimeCurrentThreadCpuTime(CVMThreadID *thread) {#ifdef CLOCK_PROCESS_CPUTIME_ID if (supportsFastThreadCpuTime) { return fastThreadCpuTime(CLOCK_THREAD_CPUTIME_ID); } else#endif { /* return user + sys since the cost is the same */ return threadCpuTimeX(&(CVMgetEE()->threadInfo), CVM_TRUE /* user + sys */); }}CVMInt64CVMtimeNanosecs(void){#ifdef CLOCK_PROCESS_CPUTIME_ID if (_clock_gettime != NULL) { struct timespec tp; int status = _clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &tp); (void)status; CVMassert(status == 0); return (CVMInt64)(((CVMInt64)tp.tv_sec) * SEC_IN_NANOSECS + (CVMInt64)tp.tv_nsec); } else#endif { struct timeval t; gettimeofday(&t, 0); return (CVMInt64)(((CVMInt64)t.tv_sec) * 1000000 + (CVMInt64)(t.tv_usec)); }}#endifCVMInt64CVMtimeMillis(void){ struct timeval t; gettimeofday(&t, 0); return (CVMInt64)(((CVMInt64)t.tv_sec) * 1000 + (CVMInt64)(t.tv_usec/1000));}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?