void os_changeThreadPriority(Thread* thread, int newPriority) { FASTIVA_LATE_IMPL(); #if 0 if (newPriority < 1 || newPriority > 10) { ALOGW("bad priority %d", newPriority); newPriority = 5; } int newNice = kNiceValues[newPriority-1]; pid_t pid = thread->systemTid; if (newNice >= ANDROID_PRIORITY_BACKGROUND) { set_sched_policy(dvmGetSysThreadId(), SP_BACKGROUND); } else if (getpriority(PRIO_PROCESS, pid) >= ANDROID_PRIORITY_BACKGROUND) { set_sched_policy(dvmGetSysThreadId(), SP_FOREGROUND); } if (setpriority(PRIO_PROCESS, pid, newNice) != 0) { std::string threadName(dvmGetThreadName(thread)); ALOGI("setPriority(%d) '%s' to prio=%d(n=%d) failed: %s", pid, threadName.c_str(), newPriority, newNice, strerror(errno)); } else { ALOGV("setPriority(%d) to prio=%d(n=%d)", pid, newPriority, newNice); } #endif }
int os_raiseThreadPriority() { /* Get the priority (the "nice" value) of the current thread. The * getpriority() call can legitimately return -1, so we have to * explicitly test errno. */ errno = 0; int oldThreadPriority = getpriority(PRIO_PROCESS, 0); if (errno != 0) { ALOGI("getpriority(self) failed: %s", strerror(errno)); } else if (oldThreadPriority > ANDROID_PRIORITY_NORMAL) { /* Current value is numerically greater than "normal", which * in backward UNIX terms means lower priority. */ if (oldThreadPriority >= ANDROID_PRIORITY_BACKGROUND) { set_sched_policy(dvmGetSysThreadId(), SP_FOREGROUND); } if (setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_NORMAL) != 0) { ALOGI("Unable to elevate priority from %d to %d", oldThreadPriority, ANDROID_PRIORITY_NORMAL); } else { /* * The priority has been elevated. Return the old value * so the caller can restore it later. */ ALOGV("Elevating priority from %d to %d", oldThreadPriority, ANDROID_PRIORITY_NORMAL); return oldThreadPriority; } } return INT_MAX; }
void os_lowerThreadPriority(int oldThreadPriority) { if (setpriority(PRIO_PROCESS, 0, oldThreadPriority) != 0) { ALOGW("Unable to reset priority to %d: %s", oldThreadPriority, strerror(errno)); } else { ALOGV("Reset priority to %d", oldThreadPriority); } if (oldThreadPriority >= ANDROID_PRIORITY_BACKGROUND) { set_sched_policy(dvmGetSysThreadId(), SP_BACKGROUND); } }
/* * native public static int nativePostForkChild(long token, int debug_flags), */ static void Dalvik_dalvik_system_ZygoteHooks_postForkChild( const u4* args, JValue* pResult) { /* * Our system thread ID has changed. Get the new one. */ Thread* thread = dvmThreadSelf(); thread->systemTid = dvmGetSysThreadId(); /* configure additional debug options */ enableDebugFeatures(args[1]); gDvm.zygote = false; if (!dvmInitAfterZygote()) { ALOGE("error in post-zygote initialization"); dvmAbort(); } RETURN_VOID(); }
/* * Initiate garbage collection. * * NOTES: * - If we don't hold gDvm.threadListLock, it's possible for a thread to * be added to the thread list while we work. The thread should NOT * start executing, so this is only interesting when we start chasing * thread stacks. (Before we do so, grab the lock.) * * We are not allowed to GC when the debugger has suspended the VM, which * is awkward because debugger requests can cause allocations. The easiest * way to enforce this is to refuse to GC on an allocation made by the * JDWP thread -- we have to expand the heap or fail. */ void dvmCollectGarbageInternal(const GcSpec* spec) { GcHeap *gcHeap = gDvm.gcHeap; u4 gcEnd = 0; u4 rootStart = 0 , rootEnd = 0; u4 dirtyStart = 0, dirtyEnd = 0; size_t numObjectsFreed, numBytesFreed; size_t currAllocated, currFootprint; size_t percentFree; int oldThreadPriority = INT_MAX; /* The heap lock must be held. */ if (gcHeap->gcRunning) { LOGW_HEAP("Attempted recursive GC"); return; } #ifdef FASTIVA // Ensure no Java-object reference is used in local-stack. // and save Java-object reference maybe in registers. Thread* self = dvmThreadSelf(); #ifdef _DEBUG gc_start_threadId = dvmGetSysThreadId(); gc_start_thread = pthread_self(); //ALOGE("##### GC_START %i", dvmGetSysThreadId()); #endif void* fastiva_old_sp; ThreadStatus oldStatus = THREAD_RUNNING; if (self != NULL) { oldStatus = self->status; jmp_buf* fastiva_buf$ = (jmp_buf*)alloca(sizeof(jmp_buf)); fastiva_old_sp = fastiva_lockStack(self, fastiva_buf$); self->status = THREAD_NATIVE; } #endif // Trace the beginning of the top-level GC. if (spec == GC_FOR_MALLOC) { ATRACE_BEGIN("GC (alloc)"); } else if (spec == GC_CONCURRENT) { ATRACE_BEGIN("GC (concurrent)"); } else if (spec == GC_EXPLICIT) { ATRACE_BEGIN("GC (explicit)"); } else if (spec == GC_BEFORE_OOM) { ATRACE_BEGIN("GC (before OOM)"); } else { ATRACE_BEGIN("GC (unknown)"); } gcHeap->gcRunning = true; rootStart = dvmGetRelativeTimeMsec(); ATRACE_BEGIN("GC: Threads Suspended"); // Suspend A dvmSuspendAllThreads(SUSPEND_FOR_GC); /* * If we are not marking concurrently raise the priority of the * thread performing the garbage collection. */ if (!spec->isConcurrent) { oldThreadPriority = os_raiseThreadPriority(); } if (gDvm.preVerify) { LOGV_HEAP("Verifying roots and heap before GC"); verifyRootsAndHeap(); } dvmMethodTraceGCBegin(); /* Set up the marking context. */ if (!dvmHeapBeginMarkStep(spec->isPartial)) { ATRACE_END(); // Suspend A ATRACE_END(); // Top-level GC LOGE_HEAP("dvmHeapBeginMarkStep failed; aborting"); dvmAbort(); } /* Mark the set of objects that are strongly reachable from the roots. */ LOGD_HEAP("Marking..."); dvmHeapMarkRootSet(); /* dvmHeapScanMarkedObjects() will build the lists of known * instances of the Reference classes. */ assert(gcHeap->softReferences == NULL); assert(gcHeap->weakReferences == NULL); assert(gcHeap->finalizerReferences == NULL); assert(gcHeap->phantomReferences == NULL); assert(gcHeap->clearedReferences == NULL); if (spec->isConcurrent) { /* * Resume threads while tracing from the roots. We unlock the * heap to allow mutator threads to allocate from free space. */ dvmClearCardTable(); dvmUnlockHeap(); dvmResumeAllThreads(SUSPEND_FOR_GC); ATRACE_END(); // Suspend A rootEnd = dvmGetRelativeTimeMsec(); } /* Recursively mark any objects that marked objects point to strongly. * If we're not collecting soft references, soft-reachable * objects will also be marked. */ LOGD_HEAP("Recursing..."); dvmHeapScanMarkedObjects(); if (spec->isConcurrent) { /* * Re-acquire the heap lock and perform the final thread * suspension. */ dirtyStart = dvmGetRelativeTimeMsec(); dvmLockHeap(); ATRACE_BEGIN("GC: Threads Suspended"); // Suspend B dvmSuspendAllThreads(SUSPEND_FOR_GC); /* * As no barrier intercepts root updates, we conservatively * assume all roots may be gray and re-mark them. */ #ifndef FASTIVA_PRELOAD_STATIC_INSTANCE dvmHeapReMarkRootSet(); #endif /* * With the exception of reference objects and weak interned * strings, all gray objects should now be on dirty cards. */ if (gDvm.verifyCardTable) { dvmVerifyCardTable(); } /* * Recursively mark gray objects pointed to by the roots or by * heap objects dirtied during the concurrent mark. */ dvmHeapReScanMarkedObjects(); } #ifdef FASTIVA_PRELOAD_STATIC_INSTANCE u4 staticScanStart = dvmGetRelativeTimeMsec(); dvmHeapReMarkRootSet(); //void fastiva_dvmHeapReScanRootObjects(); //fastiva_dvmHeapReScanRootObjects(); u4 staticScanEnd = dvmGetRelativeTimeMsec(); #endif /* * All strongly-reachable objects have now been marked. Process * weakly-reachable objects discovered while tracing. */ dvmHeapProcessReferences(&gcHeap->softReferences, spec->doPreserve == false, &gcHeap->weakReferences, &gcHeap->finalizerReferences, &gcHeap->phantomReferences); #if defined(WITH_JIT) /* * Patching a chaining cell is very cheap as it only updates 4 words. It's * the overhead of stopping all threads and synchronizing the I/D cache * that makes it expensive. * * Therefore we batch those work orders in a queue and go through them * when threads are suspended for GC. */ dvmCompilerPerformSafePointChecks(); #endif LOGD_HEAP("Sweeping..."); dvmHeapSweepSystemWeaks(); /* * Live objects have a bit set in the mark bitmap, swap the mark * and live bitmaps. The sweep can proceed concurrently viewing * the new live bitmap as the old mark bitmap, and vice versa. */ dvmHeapSourceSwapBitmaps(); if (gDvm.postVerify) { LOGV_HEAP("Verifying roots and heap after GC"); verifyRootsAndHeap(); } if (spec->isConcurrent) { dvmUnlockHeap(); dvmResumeAllThreads(SUSPEND_FOR_GC); ATRACE_END(); // Suspend B dirtyEnd = dvmGetRelativeTimeMsec(); } dvmHeapSweepUnmarkedObjects(spec->isPartial, spec->isConcurrent, &numObjectsFreed, &numBytesFreed); LOGD_HEAP("Cleaning up..."); dvmHeapFinishMarkStep(); if (spec->isConcurrent) { dvmLockHeap(); } LOGD_HEAP("Done."); /* Now's a good time to adjust the heap size, since * we know what our utilization is. * * This doesn't actually resize any memory; * it just lets the heap grow more when necessary. */ dvmHeapSourceGrowForUtilization(); currAllocated = dvmHeapSourceGetValue(HS_BYTES_ALLOCATED, NULL, 0); currFootprint = dvmHeapSourceGetValue(HS_FOOTPRINT, NULL, 0); dvmMethodTraceGCEnd(); LOGV_HEAP("GC finished"); gcHeap->gcRunning = false; #ifdef FASTIVA if (self != NULL) { self->status = oldStatus; fastiva_releaseStack(self, fastiva_old_sp); } #endif LOGV_HEAP("Resuming threads"); if (spec->isConcurrent) { /* * Wake-up any threads that blocked after a failed allocation * request. */ dvmBroadcastCond(&gDvm.gcHeapCond); } if (!spec->isConcurrent) { dvmResumeAllThreads(SUSPEND_FOR_GC); ATRACE_END(); // Suspend A dirtyEnd = dvmGetRelativeTimeMsec(); /* * Restore the original thread scheduling priority if it was * changed at the start of the current garbage collection. */ if (oldThreadPriority != INT_MAX) { os_lowerThreadPriority(oldThreadPriority); } } /* * Move queue of pending references back into Java. */ dvmEnqueueClearedReferences(&gDvm.gcHeap->clearedReferences); gcEnd = dvmGetRelativeTimeMsec(); percentFree = 100 - (size_t)(100.0f * (float)currAllocated / currFootprint); if (!spec->isConcurrent) { u4 markSweepTime = dirtyEnd - rootStart; u4 gcTime = gcEnd - rootStart; bool isSmall = numBytesFreed > 0 && numBytesFreed < 1024; ALOGD("%s freed %s%zdK, %d%% free %zdK/%zdK, paused %ums, total %ums", spec->reason, isSmall ? "<" : "", numBytesFreed ? MAX(numBytesFreed / 1024, 1) : 0, percentFree, currAllocated / 1024, currFootprint / 1024, markSweepTime, gcTime); } else { u4 rootTime = rootEnd - rootStart; u4 dirtyTime = dirtyEnd - dirtyStart; u4 gcTime = gcEnd - rootStart; bool isSmall = numBytesFreed > 0 && numBytesFreed < 1024; ALOGD("%s freed %s%zdK, %d%% free %zdK/%zdK, paused %ums+%ums, total %ums", spec->reason, isSmall ? "<" : "", numBytesFreed ? MAX(numBytesFreed / 1024, 1) : 0, percentFree, currAllocated / 1024, currFootprint / 1024, rootTime, dirtyTime, gcTime); } if (gcHeap->ddmHpifWhen != 0) { LOGD_HEAP("Sending VM heap info to DDM"); dvmDdmSendHeapInfo(gcHeap->ddmHpifWhen, false); } if (gcHeap->ddmHpsgWhen != 0) { LOGD_HEAP("Dumping VM heap to DDM"); dvmDdmSendHeapSegments(false, false); } if (gcHeap->ddmNhsgWhen != 0) { LOGD_HEAP("Dumping native heap to DDM"); dvmDdmSendHeapSegments(false, true); } ATRACE_END(); // Top-level GC }