Free tools Windows power users keep installed
One-click scans. No signup required.
Calculate characters per second (CPS) by dividing a defined character count by elapsed time in seconds. In a browser, measure the interval with performance.now(), convert milliseconds to seconds, and divide the count by that duration. For runs of unequal length, divide total characters by total time; do not average the run-level CPS values unless each run should count equally.
Define what counts as a character
JavaScript’s String.length reports UTF-16 code units, not necessarily the characters a person perceives. A supplementary Unicode code point, such as many emoji, occupies two code units. A perceived character can also consist of multiple code points—for example, an emoji joined with another symbol or a letter combined with a diacritic.
As an Amazon Associate I earn from qualifying purchases.
| Counting rule | JavaScript approach | What the count represents |
|---|---|---|
| UTF-16 code units | text.length |
JavaScript string storage units; a supplementary code point can count as two. |
| Unicode code points | [...text].length |
Code points, which may still be more than one per perceived character. |
| Grapheme clusters | new Intl.Segmenter(locale, { granularity: "grapheme" }) |
A practical count of user-perceived characters, subject to segmentation conventions and locale/runtime behavior. |
MDN explains that Intl.Segmenter provides locale-sensitive segmentation, including graphemes. Its reference marks the API Baseline 2024, so older browsers or devices may not support it. Unicode grapheme boundaries are useful conventions, not a universal definition for every language or user preference; see Unicode Standard Annex #29.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Choose the rule required by your product or test and use it consistently. For a grapheme count, for example:
#1 Best Overall
function countGraphemes(text, locale = "en") {
const segmenter = new Intl.Segmenter(locale, { granularity: "grapheme" });
return [...segmenter.segment(text)].length;
}
Measure elapsed time in seconds
performance.now() returns a high-resolution timestamp in milliseconds relative to a monotonic time origin. Subtract the start reading from the end reading, then divide by 1,000 to obtain seconds. MDN notes that timer precision may be reduced for privacy and security, and browser behavior can differ when the operating system sleeps. It is appropriate for ordinary short browser intervals; define a policy for long or sleep-sensitive measurements.
const startMs = performance.now();
// Run the activity being measured.
const endMs = performance.now();
const durationSeconds = (endMs - startMs) / 1000;
For elapsed browser timing, prefer performance.now() to Date.now(). The latter reports milliseconds since the Unix epoch and can be affected by system clock changes; it is useful when you need a calendar timestamp, not as the default elapsed-time clock. See Date.now().
Rank #2
Calculate CPS for one run
With a chosen count and a positive duration, the calculation is:
const durationSeconds = (endMs - startMs) / 1000;
const cps = count / durationSeconds;
Validate the inputs so a missing or invalid interval cannot quietly produce a misleading result:
function calculateCps(count, durationMs) {
if (!Number.isFinite(count) || count < 0) {
throw new RangeError("count must be a finite, non-negative number");
}
if (!Number.isFinite(durationMs) || durationMs <= 0) {
throw new RangeError("durationMs must be a finite, positive number");
}
return count / (durationMs / 1000);
}
For instance, 240 counted characters over 12,000 milliseconds is 240 ÷ 12 = 20 CPS. The result means only what the chosen counting rule and measured interval mean.
Combine runs with unequal durations
For runs with counts cᵢ and durations tᵢ in seconds, aggregate CPS is Σcᵢ / Σtᵢ. If durations are stored in milliseconds, divide their sum by 1,000 before calculating:
Rank #4
function aggregateCps(runs) {
const totalCount = runs.reduce((sum, run) => sum + run.count, 0);
const totalDurationMs = runs.reduce((sum, run) => sum + run.durationMs, 0);
return calculateCps(totalCount, totalDurationMs);
}
This is equivalent to weighting each run’s CPS by its duration. The plain arithmetic mean of run-level CPS gives every run equal influence, so a very short run counts as much as a long one. Use that statistic only when equal influence per run is the intended question—not when you want the rate over all combined time.
Do these 3 things before closing this tab:
1Repair Windows errors before they cause bigger problems2Scan for outdated or missing drivers - takes under a minute3Clear out junk files and repair common Windows errorsMake measurements repeatable
Keep the rate calculation separate from the code that reads the clock. Supply fixed counts and durations to a pure function in unit tests, and use live clock readings only for the actual measured interval. This makes arithmetic checks deterministic without claiming that clock-based measurements are identical from run to run.
Quick Recap
Best Value
- Use the same exact text or task inputs for comparisons.
- Record whether the count uses code units, code points, or grapheme clusters; record locale and runtime where relevant.
- Keep the timing method and start/end rules fixed.
- State whether pauses are included. Including them measures elapsed-session rate; excluding them measures active rate.
- Use predetermined values in arithmetic tests, including invalid durations, rather than relying on a live clock to test the formula.
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




