kodebeat / papers / greenops

Linting for the energy a codebase wastes

A static analyser for energy-wasteful patterns.

Flags busy loops, sub-100ms polling, every-minute crons, SELECT *, full-history CI clones, peak-sized instances and missing resource limits, across source, CI config, Terraform, manifests and Dockerfiles. Every finding explains why the pattern wastes energy and carries an order-of-magnitude gCO2e steer from four published sources. For the team with a sustainability target and no idea which line to change first.

The problem

An organisation commits to reducing the carbon footprint of its software. The sustainability team asks engineering what it plans to change. Engineering has no answer, not because it is unwilling but because no tool it runs has ever pointed at a line and said that line wastes energy.

The waste is real and it is mundane. A representative sample, all of which pass code review routinely:

# .github/workflows/ci.yml
on:
  schedule:
    - cron: '* * * * *'      # 1,440 runs a day
while True:                   # no sleep: one core, pegged, forever
    if queue.ready():
        handle(queue.pop())
SELECT * FROM orders WHERE customer_id = ?   -- 40 columns, 3 are read

None of these is a bug, and every one passes tests. The busy loop is correct: it does what it was written to do, and it does it while consuming a core continuously, roughly 150–200 gCO2e per day per instance on world-average grid intensity. The every-minute cron runs 1,440 times daily to check something that changes weekly. The SELECT * reads thirty-seven columns nobody looks at, through the disk, through the network, into memory, on every call.

There is no lint rule for any of it, so the review that would have caught a missing null check waves it through. And because none of it is broken, it never generates an incident that would prompt a fix. It simply runs, forever, costing electricity that nobody has attributed to it.

The method

Lint, don't measure. greenlint never runs your code and never builds it. One pass over the tree, and it reports patterns. This makes it fast enough to run on every commit, and it is pattern detection, not telemetry. The cost is that it can only find what a rule describes; a wasteful pattern with no rule is invisible to it.

Every finding is actionable and explained. Output is not a rule ID. It is the pattern, the reason it wastes energy, and the alternative:

$ greenlint src/ .github/
.github/workflows/ci.yml:12: [GL003/high] cron job scheduled every minute
    ↳ every-minute CI/cron jobs rarely need it; widen the schedule
src/db.py:44: [GL005/medium] SELECT * query
    ↳ fetch only needed columns; less I/O, less network, less RAM

greenlint: 2 finding(s)

AST where it matters, regex where nothing better exists. The choice is made per file type and stated plainly. Python gets a real parse — six AST rules — because a regex cannot distinguish while True: with a sleep in it from one without. CI configs, Terraform and Kubernetes manifests get regex rules, because most of the file types that waste the most energy have no parser worth carrying a dependency for.

How the regex rules avoid false positives. Before regex rules run, comment bodies are blanked to spaces with offsets preserved, and string literals are blanked the same way. Line numbers still point at the real file, but a rule about code shape stops matching the example inside a docstring, the comment block quoted into a heredoc, or the test fixture. In the README's words, this is how the regex rules "buy back the largest class of false positive a parser would have caught for free". GL004 is the documented exception: it reads comments, because that is what it is for.

The caveat the README states up front. The rule set is the product and still growing: a minor release can add findings to a tree that was clean yesterday. The recommended responses are to pin a version in CI or record a baseline.

The headline results

  • This section carries the paper, because the gram figures are the claim most likely to be challenged.
  • Everything downstream of those is arithmetic stated in a comment beside the constant.
  • The rule-level correctness argument is separate and mechanical.
  • The suite is 254 tests: 212 in tests/test_greenlint.py, 38 for the editor scan server and 4 performance checks.
  • Rule IDs are stable once published.

The full results, with the tables and the reasoning behind each figure, are in the PDF.

What is in the PDF

  • The problem — what goes unanswered without it, and who notices first.
  • Why the obvious alternative falls short — stated plainly, including where it is the better choice.
  • How it works — the method, not a feature list.
  • Concrete use cases — with console output quoted from the repository, never reconstructed.
  • The methodology behind any number it emits — every term shown, so the figure survives a question.
  • What it deliberately does not do — the section most papers leave out.

Part of the GreenOps theme.

Get the PDF

This paper already selected; the download starts when you send the form. No follow-up sequence.

Get the PDF