Get CPU/GPU/memory information
Asked Answered
M

3

54

I need to get any information about the CPU/GPU/memory.The number of cores, memory value, memory and cpu usage... I found a way to do this for IE:How to Use JavaScript to Find Hardware Information

solutions for other browsers I do not know. Any idea how to do it? maybe webgl has access to information about your computer? or flash? or any other technology?

Thank you very much

Manutius answered 17/3, 2013 at 19:0 Comment(3)
In google chrome you can use console.memory to find out the amount of memory available in the JS heap.Georganngeorge
I'd have a look at whether a Flash shim might help. I haven't seen any cross-browser API for hardware info before.Certify
Those methods no longer work in IE. Browsers are trying to make it harder to track people. One way to track people is to look up all the info about their machine. That plus their ip address is often enough to identify someone or a least a specific machine. So, browser don't show CPU/GPU/Memory/# cores/etc. (panopticlick.eff.org)Heretofore
B
39

This code will print GPU info and will list all info you can get from the Performance object of this browser (it's different for each browser).

<html>

<body>
  <canvas id="glcanvas" width="0" height="0"></canvas>
  <script>
    var performance = window.performance || window.mozPerformance || window.msPerformance || window.webkitPerformance || {};

    const performanceKeys = [];
    for (var value in performance) {
      performanceKeys.push(value);
    }
    document.write("<br>");
    document.write(performanceKeys.sort().map((p) => '<a href="https://developer.mozilla.org/en-US/docs/Web/API/Performance/' + p + '">' + p + "</a>").join("<br>"));
    document.write("<br>");

    document.write("<br><br><br>");

    var canvas;
    canvas = document.getElementById("glcanvas");
    var gl = canvas.getContext("experimental-webgl");

    document.write(gl.getParameter(gl.RENDERER) + "<br>");
    document.write(gl.getParameter(gl.VENDOR) + "<br>");
    document.write(getUnmaskedInfo(gl).vendor + "<br>");
    document.write(getUnmaskedInfo(gl).renderer + "<br>");


    function getUnmaskedInfo(gl) {
      var unMaskedInfo = {
        renderer: '',
        vendor: ''
      };

      var dbgRenderInfo = gl.getExtension("WEBGL_debug_renderer_info");
      if (dbgRenderInfo != null) {
        unMaskedInfo.renderer = gl.getParameter(dbgRenderInfo.UNMASKED_RENDERER_WEBGL);
        unMaskedInfo.vendor = gl.getParameter(dbgRenderInfo.UNMASKED_VENDOR_WEBGL);
      }

      return unMaskedInfo;
    }
  </script>
</body>

Output in Chrome:

addEventListener
clearMarks
clearMeasures
clearResourceTimings
dispatchEvent
eventCounts
getEntries
getEntriesByName
getEntriesByType
mark
measure
memory
navigation
now
onresourcetimingbufferfull
removeEventListener
setResourceTimingBufferSize
timeOrigin
timing
toJSON



WebKit WebGL
WebKit
NVIDIA Corporation
NVIDIA GeForce GTX 775M OpenGL Engine

Output in Firefox:

addEventListener
clearMarks
clearMeasures
clearResourceTimings
dispatchEvent
eventCounts
getEntries
getEntriesByName
getEntriesByType
mark
measure
navigation
now
onresourcetimingbufferfull
removeEventListener
setResourceTimingBufferSize
timeOrigin
timing
toJSON



Mozilla
Mozilla

Output in Safari:

addEventListener
clearMarks
clearMeasures
clearResourceTimings
dispatchEvent
getEntries
getEntriesByName
getEntriesByType
mark
measure
navigation
now
onresourcetimingbufferfull
removeEventListener
setResourceTimingBufferSize
timeOrigin
timing
toJSON



WebKit WebGL
WebKit
NVIDIA Corporation
NVIDIA GeForce GTX 775M OpenGL Engine
Brogan answered 15/8, 2016 at 7:20 Comment(3)
detects Nvidia Geforce GTX 960M (laptop) as GTX 980 (desktop)Rubinrubina
If you're interested in this question, you may like to know that Firefox has started "bucketing" GPU names -- quite a lot of GPUs now show up as "GTX 980". It's an anti-fingerprinting measure.Silda
These days the only difference is that Chrome has performance.memory (deprecated) and Safari doesn't have performance.eventCounts.Hollishollister
P
14

Currently Chrome Canary supports returning the amount of CPU cores using:

navigator.hardwareConcurrency

This worked for me in Chrome Canary 37.

Pyrometallurgy answered 15/6, 2014 at 12:41 Comment(6)
Works in Chrome 40 stable.Farina
I wrote about hardwareConcurrency in other browsers here: https://mcmap.net/q/340161/-is-there-a-way-to-know-anything-about-hardware-resources-of-39-platform-39-accessing-webpagePreposterous
Is this cores or threads? Because when I did this I got the number 4 back, but my processor only has two cores (it does have 4 threads though). I'm guessing this is because I have an i7?Cheapjack
According to wiki.whatwg.org/wiki/Navigator_HW_Concurrency it returns the number of logical processors available to the user agent, up to an optional thread limit per origin.Pyrometallurgy
@Johannes with processors supporting Hyperthreading the system sees your double core processor as quad core. Not browsers only, but OS itself.Syrian
Also implemented in firefox as of now.Frigidarium
S
12

Estimate CPU speed by timing how long it takes to decrement a variable millions of times:

const runs = 150000000;
const start = performance.now(); // in ms, usually with 100us resolution
for (let i = runs; i>0; i--) {}
const end = performance.now();
const ms = end - start;
const cyclesPerRun = 2;
const speed = (runs / ms / 1000000) * cyclesPerRun;
console.log(`Time: ${Math.round(ms)/1000}s, estimated speed: ${Math.round(speed*10)/10} GHz`);

* cyclesPerRun is a very rough way to map "subtractions per second" to clock speed and it varies a lot across browsers (because their JavaScript engines might optimize the code differently) and CPUs (because they might be able to pipeline more instructions, they might ramp up their frequency faster, etc.). You might be better off just using runs / ms as a generic "CPU speed" parameter instead of trying to estimate the clock speed in GHz with cyclesPerRun.

You can also estimate cyclesPerRun yourself by running the code above on a CPU you know the clock speed of and then doing this:

const knownSpeed = 3.2; // GHz
const estimatedCyclesPerRun = knownSpeed / (runs/ms/1000000);
console.log("cyclesPerRun = " + estimatedCyclesPerRun);

Also this benchmark depends on the number of browser tabs the user has open or if some other program (like a video game) is already using the computer's resources, etc.

Sihonn answered 9/2, 2017 at 17:50 Comment(18)
Well.. I guess it's accurate if you tweak the _speedconstant for "your" machine, because running this in my 4-year-old machine estimates 23.753GHz. This is also susceptible to javascript engine optimizations.Sopping
@Sopping Yep, it is not the most reliable, but I found that it is good for a quick client-side approximate estimate of CPU speed, for mobile devices especially. I have used it in the past when other solutions like the first one fail, or when the browser cannot be identified. I can see your point though, it doesn't really work on PCs with JS optimizations or multiple cores :)Sihonn
Yes, that's definitely better than nothing.... I will consider the output of this method as a generic "JS speed value" more than the GHz of the processor, which is more than enough to optimize the app to the power of the machine.Sopping
@Sopping Good idea :)Sihonn
Tried this script on Intel Core i7 iMac (late 2013) model at 3.1GHz, it reports 7.7GHz... seems quite inaccurate.Marcelo
We used this technic in 1999, when my computer had < 100Mhz and a for loop with 10000 empty iterations took 1 second.Katharinakatharine
I'm also getting 7.89Ghz on a processor that boosts up to 4.9Ghz but usually runs at more like 3.7 (i9-11950H). It's worth noting that most modern processors have highly variable speeds. It seems like thie benchmark constant needs a /2 somewhere at the end because of some perf improvement in V8 perhaps? e.g. var _speedconstant = 4.5e-9; gives 3.75Ghz for me, which is a lot closer to realistic, but would need to profile on several CPUs to test. Of note it works if I 4x the amount val, but if I 8x it, it goes way off and estimates 0.58Ghz. Also: would be ideal to run this in a webworker.Too
It works fine, as expected for me :) I am getting 3.36GHz on a Ryzen 5 2600 on Win 10 in Google ChromeGreasewood
@KyleBaker: Perhaps V8 unrolls while JIT-compiling, into an asm loop that does sub eax, 2 / jge keep_looping or something, to do 2 source-iterations per asm iteration. Or unrolling more but using floating-point math (which has higher latency thus a longer loop-carried dependency chain) since it's Javascript. This counted-loop benchmark idea sounds is tremendously error-prone and dependent on how a JIT-compiler optimizes it into asm. And if it runs long enough, will spend extra time re-optimizing it.Chemosmosis
So not only do you have CPU frequency ramp-up, you have different JIT optimizers on different browsers or node.js versions. This seems very error-prone, and only usable for different CPUs with the same JS implementations.Chemosmosis
@PeterCordes but in a different sense, it's also the only true answer if you want to know the cpu speed because it directly measures how many nanoseconds it takes to perform a subtraction and a conditional jump (FLOPS effectively). I would assume that all modern JIT'd implementations (there's only 3 that matter) would become that, and because it's doing so many iterations the warmup should be negligible. Then it's a question of instructions per floating point subtraction and pipeline depth. Treating the result as a generic "speed" value and not directly as GHz is a good suggestion.Hollishollister
@BorisVerkhovskiy The major JS JIT engines are very capable of using integer math for JS operations when they can prove that the value is always an integer. Like in this case, runs is initialized with an integer value (in range for int32 so FP math on it will be exact) and only has integer subtraction done on it, so it's an easy and important optimization that JITs would definitely look for. (If it was using FP, it wouldn't be measuring max FLOPS, it would bottleneck on FP subtract latency. e.g. one subtract per 4 clocks on Intel Skylake, vs. 2/clock for independent scalar subtracts.)Chemosmosis
@BorisVerkhovskiy: A better designed loop could be a lot less likely to get optimized or unrolled, e.g. start with x = 2^52 - 1e7 or something, and add x += 0.999 until x stops changing. A non-integer increment will require FP math, which is not associative and can't be easily unrolled. Once it gets to 2^52 or 2^53, I forget which, adding 0.99 to a double won't increase it because adjacent representable doubles are 2 apart. Of course then you're benchmarking FP math addition latency, so i7-5xxx (Broadwell) would benchmark 5/3 x faster than an i7-4xxx (Haswell), so that's not greatChemosmosis
@BorisVerkhovskiy: correction: en.wikipedia.org/wiki/… - it's 2^53 where doubles start rounding to multiples of 2, where x + 0.99 == x will be true. (And or x + 1 == x since the nearest-even tiebreak will round down at some point.)Chemosmosis
Fair enough, I assumed it didn't because it but it seems slightly unsafe, what if you iterate past MAX_SAFE_INTEGER? I don't have a laptop with me right now, but I would honestly love to check out exactly what instructions it ends up running, I saw Node.js has options to print out bytecode and assembly. Like I said, there's only 3 JS runtimes that matter (and almost everyone's using the latest versions) and there's a fairly manageable number of different CPUs in existence.Hollishollister
@BorisVerkhovskiy: If a JIT can't prove that a value won't grow so large that FP rounding needs to take effect, it could use 32-bit integers and check for overflow out of their range. 32-bit array indices are fine for most things. (Overflow of 32 bits is still cheap in asm, e.g. add eax, 1 sets CF when it wraps.) If a JIT can prove that a loop counter will stay in a safe range, it can check outside the loop and only use integer work inside the loop. e.g. for(i = 0 ; i< n ;i++) without other modification of i will only loop to n-1, so check that once.Chemosmosis
@BorisVerkhovskiy: Yeah, now that you mention it, I'm a bit curious what asm we'd get for this empty loop for x86-64, vs. my suggestion for an FP loop. How to view the assembly code generated from my JavaScript (in Chrome)?Chemosmosis
I ran node --trace-turbo <( echo "for (let i = 150000000; i>0; i--) {}") and loaded the resulting file into Turbolizer and it's definitely using integer instructions.Hollishollister

© 2022 - 2024 — McMap. All rights reserved.