Show CPU# and utime/stime in the Dalvik thread dump.
This adds the "CPU number last executed on" from /proc/stat to
the Dalvik thread output. This may come in handy when looking at
thread dumps. While I was at it I added the utime/stime values,
which may not be all that useful since they represent lifetime usage
rather than recent usage.
Output appears on the schedstat line:
| schedstat=( 2930542006 9197204583 1284 ) ut=287 st=6 core=0
The routine that parses /proc/stat, previously only used for DDMS, has
been generalized. This also fixes a problem with parsing threads
whose name includes a space.
I also changed this and the /proc/schedstat code to use /proc/self
instead of /proc/%d + getpid().
Bug 2884342.
Change-Id: Iec85bc929005044427ebbb468bfa0c9693444bca
diff --git a/vm/Misc.c b/vm/Misc.c
index 2a1e244..b4c8a6a 100644
--- a/vm/Misc.c
+++ b/vm/Misc.c
@@ -715,3 +715,120 @@
}
return base;
}
+
+
+/*
+ * Get some per-thread stats.
+ *
+ * This is currently generated by opening the appropriate "stat" file
+ * in /proc and reading the pile of stuff that comes out.
+ */
+bool dvmGetThreadStats(ProcStatData* pData, pid_t tid)
+{
+ /*
+ int pid;
+ char comm[128];
+ char state;
+ int ppid, pgrp, session, tty_nr, tpgid;
+ unsigned long flags, minflt, cminflt, majflt, cmajflt, utime, stime;
+ long cutime, cstime, priority, nice, zero, itrealvalue;
+ unsigned long starttime, vsize;
+ long rss;
+ unsigned long rlim, startcode, endcode, startstack, kstkesp, kstkeip;
+ unsigned long signal, blocked, sigignore, sigcatch, wchan, nswap, cnswap;
+ int exit_signal, processor;
+ unsigned long rt_priority, policy;
+
+ scanf("%d %s %c %d %d %d %d %d %lu %lu %lu %lu %lu %lu %lu %ld %ld %ld "
+ "%ld %ld %ld %lu %lu %ld %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu "
+ "%lu %lu %lu %d %d %lu %lu",
+ &pid, comm, &state, &ppid, &pgrp, &session, &tty_nr, &tpgid,
+ &flags, &minflt, &cminflt, &majflt, &cmajflt, &utime, &stime,
+ &cutime, &cstime, &priority, &nice, &zero, &itrealvalue,
+ &starttime, &vsize, &rss, &rlim, &startcode, &endcode,
+ &startstack, &kstkesp, &kstkeip, &signal, &blocked, &sigignore,
+ &sigcatch, &wchan, &nswap, &cnswap, &exit_signal, &processor,
+ &rt_priority, &policy);
+
+ (new: delayacct_blkio_ticks %llu (since Linux 2.6.18))
+ */
+
+ char nameBuf[64];
+ int i, fd;
+
+ /*
+ * Open and read the appropriate file. This is expected to work on
+ * Linux but will fail on other platforms (e.g. Mac sim).
+ */
+ sprintf(nameBuf, "/proc/self/task/%d/stat", (int) tid);
+ fd = open(nameBuf, O_RDONLY);
+ if (fd < 0) {
+ LOGV("Unable to open '%s': %s\n", nameBuf, strerror(errno));
+ return false;
+ }
+
+ char lineBuf[512]; /* > 2x typical */
+ int cc = read(fd, lineBuf, sizeof(lineBuf)-1);
+ if (cc <= 0) {
+ const char* msg = (cc == 0) ? "unexpected EOF" : strerror(errno);
+ LOGI("Unable to read '%s': %s\n", nameBuf, msg);
+ close(fd);
+ return false;
+ }
+ close(fd);
+ lineBuf[cc] = '\0';
+
+ /*
+ * Skip whitespace-separated tokens. For the most part we can assume
+ * that tokens do not contain spaces, and are separated by exactly one
+ * space character. The only exception is the second field ("comm")
+ * which may contain spaces but is surrounded by parenthesis.
+ */
+ char* cp = strchr(lineBuf, ')');
+ if (cp == NULL)
+ goto parse_fail;
+ cp++;
+ for (i = 2; i < 13; i++) {
+ cp = strchr(cp+1, ' ');
+ if (cp == NULL)
+ goto parse_fail;
+ }
+
+ /*
+ * Grab utime/stime.
+ */
+ char* endp;
+ pData->utime = strtoul(cp+1, &endp, 10);
+ if (endp == cp+1)
+ LOGI("Warning: strtoul failed on utime ('%.30s...')\n", cp);
+
+ cp = strchr(cp+1, ' ');
+ if (cp == NULL)
+ goto parse_fail;
+
+ pData->stime = strtoul(cp+1, &endp, 10);
+ if (endp == cp+1)
+ LOGI("Warning: strtoul failed on stime ('%.30s...')\n", cp);
+
+ /*
+ * Skip more stuff we don't care about.
+ */
+ for (i = 14; i < 38; i++) {
+ cp = strchr(cp+1, ' ');
+ if (cp == NULL)
+ goto parse_fail;
+ }
+
+ /*
+ * Grab processor number.
+ */
+ pData->processor = strtol(cp+1, &endp, 10);
+ if (endp == cp+1)
+ LOGI("Warning: strtoul failed on processor ('%.30s...')\n", cp);
+
+ return true;
+
+parse_fail:
+ LOGI("stat parse failed (%s)\n", lineBuf);
+ return false;
+}