Last active
December 19, 2017 19:56
-
-
Save dpsoft/e38685836cf7553b4fc0a2fb6bd44d1c to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
object Process { | |
type UserTime = Long | |
type KernelTime = Long | |
type StartTime = Long | |
//Hertz (number of clock ticks per second) of your system. | |
val Hz: Long = executeCmd("getconf CLK_TCK").map(_.toLong).getOrElse(100L) | |
/** | |
* A process is an instance of a computer program that is being executed. | |
* | |
* @param pid process Id. | |
* @param name process name. | |
* @param uTime CPU time spent in user code, measured in clock ticks. | |
* @param sTime CPU time spent in kernel code, measured in clock ticks. | |
* @param startTime Time when the process started, measured in clock ticks. | |
*/ | |
case class Process(pid:Int, name:String, uTime:UserTime, sTime:KernelTime, startTime:StartTime) extends Ordered[Process] { | |
override def compare(that: Process): Int = | |
java.lang.Double.compare((that.uTime + that.sTime) / that.startTime.toDouble, (this.uTime + this.sTime) / this.startTime.toDouble) | |
} | |
/** | |
* A "jiffy" is a unit of CPU time. | |
* | |
* Exactly what it corresponds to in wall-clock time depends on the architecture and how your kernel is configured, | |
* but the important thing is that /proc/stat tells you how many jiffies the CPU has executed in total | |
* and /proc/<PID>/stat tells you how many jiffies have been executed by a single process. | |
* | |
* @param pid process id | |
* @return (UserTime, KernelTime, StartTime) in jiffies | |
*/ | |
def jiffiesByProcess(pid: Long): (UserTime, KernelTime, StartTime) = | |
firstLineOf(s"/proc/$pid/stat").map { line => | |
val values = line.split(" ") | |
val uTime = Option(values(13).toLong).getOrElse(0L) * 1000L / Hz | |
val sTime = Option(values(14).toLong).getOrElse(0L) * 1000L / Hz | |
val startTime = Option(values(21).toLong).getOrElse(0L) * 1000L / Hz | |
(uTime, sTime, startTime) | |
}.getOrElse((0L, 0L, 0L)) | |
private def getProcessByPid(pid:Int):Option[Process] = { | |
firstLineOf(s"/proc/$pid/stat").map { line => | |
val values = line.split(" ") | |
//See man proc for how to parse /proc/[pid]/stat | |
val name = values(1).replaceFirst("\\(", "").replace(")", "") | |
val (uTime, sTime, startTime) = jiffiesByProcess(pid) | |
Process(pid, name, uTime, sTime, System.currentTimeMillis() - startTime) | |
} | |
} | |
private def firstLineOf(f: String): Option[String] = { | |
val src = Source.fromFile(f) | |
try src.getLines.find(_ => true) finally { | |
src.close() | |
} | |
} | |
private def executeCmd(cmd:String): Option[String] = { | |
import sys.process._ | |
Try((cmd !!).trim).toOption | |
} | |
} | |
object Pid { | |
val Digits: Pattern = Pattern.compile("\\d+") | |
/** | |
* Gets an Seq of integers in the /proc directory with only numeric digit | |
* filenames, corresponding to processes | |
* | |
* @return An Seq of integers that represents the process ids. | |
*/ | |
def getAll: Seq[Int] = Option(new File("/proc").listFiles(new FileFilter() { | |
override def accept(file: File): Boolean = | |
Digits.matcher(file.getName).matches() | |
}).toList.map(_.getName.toInt)).getOrElse(Nil) | |
} | |
object Test extends App { | |
while(true) { | |
Thread.sleep(1000) | |
println(Pid.getAll.map(p => Process.getProcessByPid(p)).sorted.take(10)) | |
} | |
} | |
//List(Some(Process(5549,Web,0,26673100,1513710984082)), Some(Process(31238,chrome,16024140,5713990,1513130505838)), Some(Process(24479,java,11861730,3099950,1512196478427)), Some(Process(1390,Xorg,6211480,4629680,1513710968296)), Some(Process(5057,firefox,6082530,2672330,1512697554152)), Some(Process(31317,chrome,5734670,2596150,1513130505249)), Some(Process(31778,chrome,5766340,513800,1513130498929)), Some(Process(1543,pulseaudio,2779660,2887010,1513710967307)), Some(Process(31807,chrome,4682150,616300,1513130494870)), Some(Process(1984,gnome-shell,3135200,423750,1512420219311))) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment