<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>Compute Gardener Blog</title>
        <link>https://www.compute-gardener.com</link>
        <description>Insights on carbon-aware computing, ML training optimization, and sustainable cloud infrastructure</description>
        <lastBuildDate>Wed, 19 Aug 2026 00:42:01 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <image>
            <title>Compute Gardener Blog</title>
            <url>https://www.compute-gardener.com/og-image.png</url>
            <link>https://www.compute-gardener.com</link>
        </image>
        <copyright>All rights reserved 2026, Compute Gardener</copyright>
        <item>
            <title><![CDATA[Nobody Cares About Carbon. Let's Build the Tools Anyway.]]></title>
            <link>https://www.compute-gardener.com/resources/blog/awareness</link>
            <guid isPermaLink="false">https://www.compute-gardener.com/resources/blog/awareness</guid>
            <pubDate>Mon, 06 Apr 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[There's no debate between carbon-aware and grid-aware computing. It's really about having some awareness or none!]]></description>
            <content:encoded><![CDATA[<p>A few months ago, <a href="https://carbonrunner.io/">CarbonRunner</a> shut down. They had built a carbon-aware CI/CD runner for GitHub Actions. They made it simple to choose the greenest region, make a one-line edit and they claimed: get faster, lower cost builds with up to 90% fewer emissions. Their shutdown notice is three bullet points, slightly shortened here:</p>
<ul>
<li><strong>Nobody cares.</strong> "People care about money, they don't seem to care about environmental savings, even if they're faster."</li>
<li><strong>The cost of switching is too high.</strong> Even a one-line change was too much friction.</li>
<li><strong>AI makes CI look cute.</strong> Datacenters keep getting built on cheap land in hot places running on coal and gas.</li>
</ul>
<p>Not "Hello world!" but "Sorry world!" they wrote. 😢🌍 "Sorry we couldn't make the internet a greener place in 2025." I don't know about you, but this one hit me hard.</p>
<p>To be fair, startup failures are rarely <em>proof</em> of market indifference. There are a hundred ways to miss product-market fit that have nothing to do with whether the underlying problem matters. But the question buried in their epitaph is still worth grappling with. The carbon case is real and already lands with a lot of engineers. The harder problem is getting it to survive contact with those engineers' boss or whoever controls the budget.</p>
<p>Meanwhile, in the research world, the state of the art keeps advancing. Researchers are publishing increasingly sophisticated multi-variable optimization frameworks. New papers demonstrate that optimizing for carbon intensity alone can, in specific scenarios, shift environmental burdens (ex: water stress, air pollution, grid congestion) to already-strained regions. The science is getting better, but adoption is flat-lining or getting worse.</p>
<hr>
<h3>The Distinction Is Real</h3>
<p>Let's define a couple terms before we go much further.</p>
<p><strong>Carbon-aware computing</strong> means responding to real-time carbon intensity signals when making scheduling decisions and running deferrable workloads when and where the grid is cleaner. This is what most tools in the space do today, including <a href="https://github.com/elevated-systems/compute-gardener-scheduler">Compute Gardener</a>, the <a href="https://github.com/Green-Software-Foundation/carbon-aware-sdk">Carbon Aware SDK</a> and what CarbonRunner did before turning off the lights.</p>
<p><strong>Grid- or sustainability-aware computing</strong> means optimizing for the broader health of the grid and the local environment, of which carbon intensity is one (often the primary) signal among several. Water stress in the datacenter's basin. Air quality near the generation source. Grid congestion and price spikes that indicate system strain. These are real dimensions that vary by region and time and they don't always move in the same direction as carbon intensity.</p>
<p>Consider what this framing implies: carbon-aware isn't competing with grid-aware. It's an instance of it; grid-aware with one signal wired in. You can't argue carbon-aware vs. grid-aware any more than you can argue Camry vs. Toyota. The debate, to the extent there is one, is about scope and signal maturity, not about whether the approach is fundamentally right.</p>
<p>Geerd-Dietger (Didi) Hoffmann and Verena Majuntke recently demonstrated this with Orca, in a paper <a href="https://www.linkedin.com/posts/dietgerhoffmann_verena-majuntke-and-my-paper-sustainability-aware-activity-7444793194942291969-MMG9">accepted</a> to <a href="https://conf.researchr.org/home/ict4s-2026">ICT4S '26</a>. In quick summary, Orca is a sustainability-aware scheduling framework that jointly optimizes across carbon, water stress, air pollution exposure and grid stress indicators. Their work is solid and the direction is true. In a three-region case study (Frankfurt, Tokyo, Northern California), they showed that CO2-optimal routing sometimes diverges from locally-optimal routing. This is observed especially when a low-carbon region happens to be water-stressed or experiencing poor air quality.</p>
<p>I recently had the chance to speak with Didi about this work and I genuinely think it moves the field forward. Optimizing for a single variable in a complex multivariate system <em>can</em> push you away from the global optimum. Any engineer who's ever tuned a system knows this intuitively. And yet...</p>
<hr>
<h3>The Correlation Is Strong With This One</h3>
<p>Here's what Orca's own data shows. In their case study, the carbon-only baseline and the multi-criteria optimum agreed on the same region for roughly two-thirds of the hours evaluated. The divergences were real but not dramatic and they were driven primarily by one region's (Japan's) persistently high water stress penalty.</p>
<p>This matches what we've seen in practice. Carbon intensity is strongly correlated with most other grid health indicators most of the time. When the grid is clean, it's usually because renewables are abundant. That, in turn, means less combustion and particulate, less water-intensive thermal generation, less air pollution from fossil plants and lower wholesale prices. The signals move together far more often than they diverge.</p>
<p>Don't get me wrong, when they do diverge, it matters. But the scenarios where carbon-optimal scheduling meaningfully worsens local outcomes generally involve specific regional characteristics. Factors such as a low-carbon grid that happens to sit in a water-stressed basin or a clean-energy window that coincides with grid congestion from other demand. These are knowable, addressable edge cases. And more than that, they're a roadmap. The divergences tell us exactly which signals to integrate next: basin-level hydrology, weather forecasting, real-time air quality, grid congestion. Not reasons to abandon carbon-aware scheduling, but the agenda for how it evolves additional dimensions of awareness.</p>
<hr>
<h3>The Signal Maturity Problem</h3>
<p>Here's the part that gets lost in the academic discussion: carbon intensity is really the only environmental signal we have that's reliable, real-time, API-accessible and globally available in a form that schedulers or routers can actually consume.</p>
<p>The additional signals that frameworks like Orca want to consider (basin-level water stress at sub-monthly resolution, real-time air quality per datacenter zone, grid congestion indicators in comparable units across jurisdictions, operator-disclosed Water Usage Effectiveness figures) are either incomplete, regional, paywalled, updated infrequently, require bespoke integration per datacenter operator or, most commonly, some combination of these.</p>
<p>Orca's own evaluation highlights missing data points throughout their air quality time series (OpenAQ gaps), simplified water modeling (WUE multiplied by a coarse stress band) and the limitation of average-mix rather than marginal emissions factors.</p>
<p>These are real concerns AND they're not yet addressable at the tooling layer because the signal infrastructure doesn't exist. Carbon intensity is the floor we can build from today. As water stress data, grid congestion signals and air quality APIs become similarly mature, they absolutely should and will be incorporated.</p>
<p>But at that point, it's a signal upgrade. Not a paradigm shift.</p>
<hr>
<h3>The Behavioral Change Is the Hard Part</h3>
<p>This is the part that matters most. And it's the part that CarbonRunner's epitaph makes impossible to ignore.</p>
<p>CarbonRunner didn't fail because they were using the wrong signal. They didn't fail because carbon-only optimization might occasionally route a CI job to a water-stressed region. They failed because, in their words, "nobody really cares."</p>
<p>The bottleneck to carbon-aware computing (or awareness of any kind) has never been signal quality. It's always been adoption. The activation energy required is organizational and cultural: classifying workloads by flexibility, shifting institutional expectations (a batch job submitted at 2am doesn't need to <em>start</em> at 2am — it just needs to <em>finish</em> by 8am), and integrating a scheduling layer that actually acts on external signals. No longer is it a "fire-and-forget" operation, but a decision with ongoing environmental (and economic) consequences. That's hard. It's unfamiliar. It requires changing habits that have been optimized for developer convenience or costs alone, not environmental awareness.</p>
<p>But here's the thing: <strong>that behavioral change only really needs to happen once.</strong> Once an organization has classified its workloads by flexibility, once it has built the scheduling infrastructure to act on external signals, once the institutional muscle memory exists, upgrading the signal set is trivial. Swapping a carbon intensity value for a multi-variable sustainability score is only a configuration change. The hard work is building organizations that can respond to any external signal at all. Getting them to respond to one unlocks responding to five. The habits transfer. The tooling upgrades.</p>
<p>The research community is doing important work improving signal quality and optimization scope. But debating whether to optimize for carbon intensity alone or a Pareto-weighted vector of carbon, water stress, NOx exposure and grid congestion is like arguing over wine pairing for a dinner that no one has RSVP'd to.</p>
<hr>
<h3>The Excused Inaction Pattern</h3>
<p>I keep seeing the same reasoning structure across different conversations in this space.</p>
<ul>
<li>"Carbon intensity doesn't capture marginal emissions accurately." → True in some contexts.</li>
<li>"Carbon-only optimization might increase water stress." → Possible in specific region+time combinations.</li>
<li>"We should fix energy markets so prices incorporate externalities, then we won't need carbon signals." → A worthy long-term goal.</li>
</ul>
<p>Every one of these is a legitimate observation about a real limitation. And every one of them, in practice, gets elevated from "limitation" to "road block" along its journey to the all-too-common destination of excused inaction.</p>
<p>It's a pattern, and once you see it in one discussion, you begin to see it everywhere.</p>
<p>To be perfectly clear: the researchers aren't "the problem." Didi's paper advances the field in exactly the right direction. <a href="https://tsukprasert.github.io/research.html">Tammy Sukprasert's work at UMass Amherst</a> on marginal vs. average signals sharpens our understanding. These are scientists doing what scientists should be doing... pushing toward more accurate models of complex systems.</p>
<p>The problem is what happens when those nuanced findings propagate into industry conversations. Even as multi-variable optimization <em>is</em> the right direction, some forces would happily weaponize its complexity as an excuse to skip earlier steps entirely. "Necessary but not sufficient" gets heard as "not necessary." "Has limitations" gets heard as "doesn't work." And the conclusion is always the same: we need to understand the problem better before we act. Which, as we know, is a wonderful way to delay action.</p>
<hr>
<h3>If We Build it, Will They Come?</h3>
<p>We're building at a time where environmental stewardship isn't just undervalued, in some markets, it's actively penalized. "Sustainability" has become a dirty word in some boardrooms which were publishing sustainability reports only two years ago. CarbonRunner didn't fail because their technology didn't work or provide the value stated. They failed because the market they were selling into doesn't yet feel sufficient pressure (whether regulatory, economic or social) to care.</p>
<p>The EU's Corporate Sustainability Reporting Directive doesn't care about the political winds in Washington. Electricity prices don't care about your feelings regarding climate change. And the physical constraints of water-stressed grids feeding power-hungry datacenters don't negotiate with anyone's politics.</p>
<p>When these pressures mount again (and they will, regardless of any single administration's or nation's posture), the question won't be "Should we optimize for sustainability?" It'll be "How fast can we start?" The organizations that already know how to flex their compute will adapt in weeks. The ones that don't will spend years trying to catch up.</p>
<p>The major cloud providers offer carbon footprint reporting. These tools are genuinely useful for compliance and retrospective accounting, but post-hoc and coarse-grained by design. They can tell you how much carbon your EC2 fleet generated last month. They cannot help you make operational decisions such as to defer your batch job four hours because the grid is dirty or electricity is cheaper in off-peak hours. That real-time, workload-level scheduling layer is precisely what's missing.</p>
<p>And this is why tools that work on economic signals alongside environmental ones matter. The rough correlation between "green" and "cheap" doesn't require a friendly regulatory regime to deliver value. At Compute Gardener, we call this our green↔cheap knob. It's a blending engine that lets organizations weigh carbon optimization against cost optimization. In environments where you can pitch sustainability, lean green. In environments where that's a dirty word and you can only pitch savings, turn the knob to cheap. The scheduling flexibility you build serves both goals, because the signals are correlated more often than not.</p>
<hr>
<h3>Where This Is Heading</h3>
<p>The research community is converging on what we might call "sustainability-aware" computing. That is, multi-variable optimization that considers carbon, water, air quality, grid health and cost as composable signals with configurable weights. That <em>is</em> the right destination.</p>
<p>At Compute Gardener, we're similarly on the journey from carbon-aware toward additional layers of awareness. Our architecture is built around a modular signal ingestion and blending engine. We use carbon intensity and electricity pricing today, with a modular design that allows incorporation of additional signals as they mature. Ultimately, the scheduler doesn't care whether its decision was based on optimizing for one variable or five. The organizational capability of classifying workloads and scheduling flexibly is the foundation. Everything built on top of that is an incremental lift.</p>
<p>Getting organizations to think about workload flexibility, to classify jobs by deferrability, to build scheduling infrastructure that responds to external signals; that's the expensive, culture-changing work. But, fortunately, it only needs to happen once. And it produces value on day one, even with carbon intensity as the only signal and even in a political environment that can't say the word "sustainability" out loud.</p>
<p>Ultimately, there's no debate between carbon-aware and grid-aware computing. If one exists, it's between awareness and unawareness. And closing that gap is where every bit of energy in this space should be focused. At the very least, it's where we continue to see value and will keep contributing.</p>
<p>Then, one day soon, new, upgraded and more reliable signals will become available. The research will keep improving. The optimization scope will broaden. But none of that matters if nobody cares.</p>
<p>You care. Start somewhere. Start now.</p>
<hr>
<p><strong>Interested in what sustainability-aware computing patterns could look like for your workloads?</strong> Whether you're running ML training, CI/CD pipelines, batch processing or any deferrable compute, we could help you quantify savings opportunities. Check out our <a href="https://github.com/elevated-systems/compute-gardener-scheduler">open-source Kubernetes scheduler</a> or <a href="https://www.compute-gardener.com/contact">reach out about a consulting engagement</a> and we can continue the conversation considering your particular infrastructure.</p>
<hr>
<p><em><a href="https://www.linkedin.com/in/davemasselink/">Dave Masselink</a> builds carbon/grid/sustainability-aware scheduling and routing tools at <a href="https://www.compute-gardener.com">Compute Gardener</a>. He's pretty sure the hardest part of sustainable computing is spurring action and has little to do with deciding the correct signal(s) to consider.</em></p>]]></content:encoded>
            <enclosure url="https://www.compute-gardener.com/blog/images/legoWaterSignals.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[The Grid Isn't a Cluster: What Technologists Get Wrong About Energy]]></title>
            <link>https://www.compute-gardener.com/resources/blog/grid-fallacies</link>
            <guid isPermaLink="false">https://www.compute-gardener.com/resources/blog/grid-fallacies</guid>
            <pubDate>Fri, 09 Jan 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Mental models from software don't always make sense when applied to electrical grids. How should we think about energy and emissions?]]></description>
            <content:encoded><![CDATA[<p><em>Mental models from software don't always make sense when applied to electrical grids. How should we think about energy and emissions?</em></p>
<hr>
<h3>Why Write This?</h3>
<p>I keep having the same conversations... with smart engineers, genuinely trying to understand carbon-aware computing. But sometimes they raise concerns/objections that sound reasonable yet rest on flawed assumptions about how the grid actually works.</p>
<p>The objections sometime sound like:</p>
<ul>
<li>"If you use clean energy, someone else gets pushed to dirty energy"</li>
<li>"Shifting load will destabilize the grid"</li>
<li>"Marginal emissions are what matter, not average intensity"</li>
<li>"This only works if we have 90%+ renewables. And then, does it even matter?"</li>
<li>"Wait, you want my $$$$ GPUs to sit idle?"</li>
</ul>
<p>These aren't dumb people. I think they're trying hard to understand. They're voicing sophisticated <em>sounding</em> concerns that happen to be wrong. Or at least, misguided in ways that would end up confounding practical decision-making.</p>
<p>The problem: technologists think about grids like they think about compute clusters. More-or-less fixed capacity. Zero-sum allocation. Deterministic scheduling.</p>
<p>But grids aren't clusters. They're economic systems with markets, slack, planning horizons and operators who adapt to ever-changing patterns.</p>
<hr>
<h3>Fallacy 1: Musical Chairs 🪑</h3>
<p><strong>The claim:</strong> "Clean energy is limited. When you take it, someone else gets pushed onto fossil power. Net effect: zero... or worse"</p>
<p><strong>Why it sounds right:</strong> In a datacenter, if you take a CPU core, someone else can't use it. Fixed resources, zero-sum allocation.</p>
<p><strong>Why it's wrong:</strong> Grids aren't fixed-size resource pools.</p>
<p>When you move load from Virginia's fossil heavy grid (~500 gCO2eq/kWh) to Quebec's hydro powered grid (~50 gCO2eq/kWh):</p>
<ul>
<li>You don't "take" someone's hydro electrons</li>
<li>Quebec doesn't tell existing customers "sorry, you get coal now"</li>
<li>Quebec responds by... continuing to run hydro, because that's what it always has</li>
<li>At worst, Quebec's marginal intensity bumps slightly — maybe to 55 gCO2eq/kWh</li>
<li>Your compute still runs at ~1/10th the intensity compared to Virginia</li>
</ul>
<p><strong>The better mental model:</strong> Markets, not resource pools.</p>
<p>Buying more EVs doesn't force someone else to buy a gas car. It shifts demand curves and production incentives over time. It's the same with clean electricity; sustained demand in clean regions signals investment in more clean capacity.</p>
<hr>
<h3>Fallacy 2: The Fragile Grid 🩹</h3>
<p><strong>The claim:</strong> "Sudden load shifts trigger fossil backup, raise prices and risk grid instability."</p>
<p><strong>Why it sounds right:</strong> Grids must balance supply and demand in real-time. Imbalances cause blackouts. Therefore, moving load = dangerous.</p>
<p><strong>Why it's wrong:</strong> Grids are designed for variable load. Your compute job is not even a rounding error.</p>
<p><strong>Scale check — what actually stresses grids:</strong></p>
<table>
<thead>
<tr>
<th>Concern</th>
<th>Threshold</th>
<th>Your Job a concern?</th>
</tr>
</thead>
<tbody>
<tr>
<td>Frequency response</td>
<td>100+ MW in &#x3C;1 second</td>
<td>No</td>
</tr>
<tr>
<td>Ramping stress</td>
<td>1+ GW in &#x3C;15 min</td>
<td>No</td>
</tr>
<tr>
<td>Forecast error</td>
<td>Unexpected GW-scale swings</td>
<td>Too small and relatively predictable</td>
</tr>
</tbody>
</table>
<p>Remember, here are just a few things the grid can support every day, without incident:</p>
<ul>
<li>Millions of air conditioners cycling on/off</li>
<li>"it's half-time" → everyone opens their fridge and starts the [microwave] oven within a few seconds</li>
<li>Cloud cover rolls across solar farms</li>
<li>Morning demand ramps as cities wake up (or in the afternoon on solar-heavy grids)</li>
</ul>
<p>Even if the largest data centers are relevant loads, individual compute runs/jobs hardly ever are. What is your batch job running over a couple hours? Even if it were meaningful in magnitude, grid operators would see it as <em>predictable baseload</em>. Practically a gift.</p>
<p><strong>Rule of thumb:</strong> If your facility isn't comparable to an aluminum smelter (500MW+ constant draw), you're not a grid stability concern. You're a rather simple customer.</p>
<hr>
<h3>Fallacy 3: The Thundering Herd 🐏</h3>
<p><strong>The claim:</strong> "If everyone adopts carbon-aware scheduling, all load shifts to the same clean windows and crashes the grid."</p>
<p><strong>Why it sounds right:</strong> Classic distributed systems problem. Everyone retries at the same time → system overload.</p>
<p><strong>Why it's wrong:</strong> Three reasons.</p>
<p><strong>1. Optimization spreads load, it doesn't synchronize it.</strong></p>
<p>Carbon-aware schedulers don't fire every possible job in a single millisecond. They spread deferrable work across clean windows that are typically <em>hours</em> long. The "thundering herd" assumes everyone has identical deadlines and zero flexibility; but that's not the case for large swathes of deferrable compute.</p>
<p><strong>2. The Invisible Hand steps in.</strong></p>
<p>If too much load clusters in clean windows, wholesale prices rise and some load shifts back. This is how markets work. The equilibrium point isn't "everyone stampedes to 2pm." It's "2pm is more clean, but only carbon-sensitive loads may care."</p>
<p><strong>3. Grid operators aren't NPCs.</strong></p>
<p>Indepentent System Operators (ISOs) observe patterns and adapt. Load clustering at low-carbon hours? They schedule more generation for those hours. This is literally their job. The "optimization breaks everything" scenario assumes operators don't respond to changing demand; but theirs is a profession built on forecasting.</p>
<hr>
<h3>Fallacy 4: The Idle GPU 🤑</h3>
<p><strong>The claim:</strong> "Carbon-aware scheduling means expensive hardware sits unused during dirty windows."</p>
<p><strong>Why it sounds right:</strong> If you defer work during high-carbon periods, the GPUs must not be earning their keep.</p>
<p><strong>Why it's wrong:</strong> Deferral ≠ idleness. In practice, it becomes a prioritization signal and mechanism.</p>
<p>In a world with carbon-aware scheduling:</p>
<ul>
<li>Urgent, high-value work runs whenever it wants, including during dirty windows (at an implicit carbon premium)</li>
<li>Deferrable, speculative work shifts to cleaner windows</li>
<li>Total energy utilization may stay the same — but total system emissions <em>drop</em>!</li>
</ul>
<p>Nobody's $$$$ GPUs are less than fully amortized! Market participants are simply influenced differently by the same signals. Think of congestion pricing on the roads. Rush hour doesn't mean empty highways. Discretionary trips shift; essential trips don't.</p>
<hr>
<h3>Fallacy 5: "Just Build More Renewables" 🌞</h3>
<p><strong>The claim:</strong> "Carbon-aware scheduling is a distraction. We just need more clean generation."</p>
<p><strong>Why it sounds right:</strong> When the grid is 100% clean, timing shouldn't matter. Focus on the supply side.</p>
<p><strong>Why it's incomplete:</strong> It's a classic "yes, and..." situation. Even with abundant clean generation, you need:</p>
<ul>
<li>Transmission capacity to move it</li>
<li>Storage to buffer intermittency</li>
<li>Grid stability services (frequency response, voltage support)</li>
</ul>
<p>Flexible load (demand that can shift to match supply) is <em>valuable infrastructure</em>. It helps integrate renewables by absorbing variability. Carbon-aware compute isn't just about finding clean energy; it's about being a good grid citizen, facilitating more renewables coming online more quickly.</p>
<p>Clean capacity buildout and demand flexibility aren't competing strategies. They stack and complement each other.</p>
<hr>
<h3>Fallacy 6: Marginal Absolutism 💯</h3>
<p><strong>The claim:</strong> "Average grid intensity doesn't tell you your actual impact. Only marginal emissions matter."</p>
<p><strong>Why it sounds right:</strong> Economically, marginal analysis <em>is</em> often correct. Your load <em>is</em> (mostly) served by whatever generator ramps up to meet it, not the grid average.</p>
<p><strong>Why it's incomplete:</strong> We're still talking about meager loads. And especially when it comes to spatial shifting, marginal vs. average differences barely matter.</p>
<ul>
<li>Quebec's marginal source (hydro or imports from hydro-heavy neighbors) is (still much) cleaner than Virginia's marginal source (gas)</li>
<li>The 10-15x intensity gaps between clean and dirty grids outweigh most marginal nuances</li>
</ul>
<p><strong>When it can matter more:</strong> Temporal shifting within a single grid with high renewable variability. The "cleanest" hour by average intensity might not be the hour with lowest marginal impact.</p>
<p><strong>For most practical decisions:</strong> If you're choosing between Region A or B... Or you're choosing when, within a single grid, to run... average intensity is usually, at least, directionally correct. Don't let perfect be the enemy of good.</p>
<hr>
<h3>What Grid Operators Actually Care About ⚙️</h3>
<p><strong>They need to know:</strong></p>
<ul>
<li>New large facilities (100+ MW sustained) — capacity planning</li>
<li>Major industrial additions (smelting furnaces, fabs, large datacenters) — transmission planning</li>
<li>Demand response program participation — operational planning</li>
</ul>
<p><strong>They like to know:</strong></p>
<ul>
<li>Regional datacenter expansion trends</li>
<li>EV charging pattern shifts</li>
<li>Large commercial load forecasts</li>
</ul>
<p><strong>They care about:</strong></p>
<ul>
<li>Reliability</li>
<li>Reliability</li>
<li>Reliability - this isn't a joke</li>
</ul>
<p><strong>They don't care about:</strong></p>
<ul>
<li>Your 100 GPU cluster's schedule</li>
<li>Whether your training job runs at 2am, 2pm or whenever</li>
<li>Individual workload optimizations</li>
</ul>
<p><strong>But WE are allowed to care. Afterall, we all have lungs.🍃</strong></p>
<hr>
<h3>The Bottom Line</h3>
<p>Grids are resilient, adaptive, market-driven systems operated by the most responsible professionals you can possibly imagine. They've been balancing variable load for a century. The grid handles unexpected weather, sporting event demand synchs and large-scale industrial swings daily.</p>
<p>Your carbon-aware practices aren't going to break anything. ❤️ They will:</p>
<ul>
<li>Send demand signals toward clean regions → investment follows</li>
<li>Shift flexible load to times/places with abundant clean supply → better utilize what's already clean</li>
<li>Make you a more predictable, valuable customer → grid operators will like you 🎉💃🏽</li>
</ul>
<p>Barriers to carbon-aware computing are real: operational complexity, data residency, latency requirements. "Grid stability" shouldn't be one of them.</p>
<p>Stop worrying about breaking the grid. Instead, optimize away carbon emissions today!</p>
<p><strong><a href="/contact">Let's figure out your carbon optimization opportunity →</a></strong></p>
<hr>
<p><em><a href="https://github.com/elevated-systems/compute-gardener-scheduler">Compute Gardener</a> is an open-source project focused on making carbon-aware computing simpler. Join us in moving sustainable computing forward.</em></p>]]></content:encoded>
            <enclosure url="https://www.compute-gardener.com/blog/images/legoFlowerMistakes.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[Making ML Training Carbon-Aware with Compute Gardener (Part 3)]]></title>
            <link>https://www.compute-gardener.com/resources/blog/ml-training-carbon-aware-pt3</link>
            <guid isPermaLink="false">https://www.compute-gardener.com/resources/blog/ml-training-carbon-aware-pt3</guid>
            <pubDate>Thu, 18 Dec 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[Part 3 details experimentation around carbon-aware, spatial scheduling of LoRA fine-tuning.]]></description>
            <content:encoded><![CDATA[<p><em>We routed 21 training jobs to the cleanest available region. Norway won every time, reducing emissions 93% vs. the Ohio baseline. But the real lesson is simpler than we expected.</em></p>
<hr>
<h3>The Story So Far</h3>
<p>In <a href="/resources/blog/ml-training-carbon-aware-pt1">Part 1</a>, we showed that shifting ML training jobs to cleaner time windows could reduce carbon emissions by ~30%. In <a href="/resources/blog/ml-training-carbon-aware-pt2">Part 2</a>, we scaled up to a real hyperparameter search, 21 LoRA fine-tuning experiments orchestrated with Ray, and achieved 40% reductions in carbon emissions using a tiered scheduling strategy.</p>
<p>Both experiments used Compute Gardener's scheduler to make <em>temporal</em> decisions: not <em>whether</em> to run a job, but <em>when</em>. And both ran on hardware in our lab — GPUs we own, in a single location, drawing from a single grid region.</p>
<p>Part 3 asks a different question: what if we could choose <em>where</em> to run?</p>
<h3>Why Spatial Shifting Matters</h3>
<p>Temporal shifting works because grid carbon intensity varies throughout the day. But it also varies <em>across</em> grids — dramatically. At any given moment, Oregon's hydro-heavy grid might be running at 80 gCO2/kWh while Virginia's gas-heavy grid sits at 350. That's more than a 4x difference, available instantly, no waiting required.</p>
<p>For most ML scientists and engineers, this is probably more accessible than temporal shifting. You may not have a dedicated lab with GPUs and a Kubernetes scheduler you control. But you <em>can</em> (sometimes) choose a cleaner cloud region to spin up your training job in. The question is whether anyone actually does — and whether the savings justify the effort.</p>
<h3>Why Another Experiment?</h3>
<p>The academic literature is full of simulations showing 20-40% potential savings from spatial shifting. Could a simulation predict that clean grids beat dirty ones? Sure. But simulations don't tell you whether Vast.ai actually maintains GPU availability across regions, whether Tailscale works reliably across continents, whether the Electricity Maps API is stable enough for real-time routing or whether a prototype can be setup in an afternoon.</p>
<p>Part 3 extends our real-world testing to cloud infrastructure; where most ML training actually happens. The experiment validates operational feasibility, not just theoretical carbon math.</p>
<h3>An Experiment in Routing</h3>
<p>Compute Gardener's scheduler currently handles temporal shifting within a single cluster. Spatial shifting is on the roadmap, but rather than wait for the perfect design, we experimented with the simplest approach: a routing script that checks carbon intensity across three regions and sends each job to the cleanest one.</p>
<p>This isn't what a production spatial shifting system would look like. (For anyone curious, we'll probably build on top of a gitops or hub+spoke multi-cluster strategy.) But it's small enough to build quickly and honest enough to teach us where the complexity actually lives.</p>
<h3>The Setup</h3>
<p>We kept the workload familiar: LoRA fine-tuning of Qwen2.5-Coder-7B, the same model from Part 2. But we stripped the infrastructure down to essentials: no Kubernetes, no Ray orchestration. Just three GPU instances, SSH and a routing script.</p>
<p><strong>Three regions, three grid profiles:</strong></p>
<ul>
<li><strong>Quebec</strong>: Hydro-Quebec grid, one of the cleanest grids in North America. A viable clean option that's geographically close for US-based teams.</li>
<li><strong>Ohio</strong>: PJM grid, gas/coal-heavy, typically the highest carbon intensity of our three options. Representative of the "default" US East/Virginia/Midwest data centers where most workloads already run.</li>
<li><strong>Norway</strong>: Nordic grid, among the cleanest in the world due to hydro dominance. The "what if we could route to fundamentally different energy infrastructure" option.</li>
</ul>
<p>We chose these regions to represent a practical range: the status quo (Ohio/Virginia), a clean North American alternative (Quebec) and an aspirational clean option (Norway). This creates a stark contrast — that's intentional. The question isn't whether clean grids exist, but whether dynamic routing into such a pool is accessible or necessary.</p>
<p><strong>Hardware:</strong> NVIDIA RTX 4090 GPUs (24GB VRAM) rented via <a href="https://vast.ai">Vast.ai</a> in Quebec, Ohio and Norway.</p>
<p><strong>Network:</strong> Tailscale VPN connecting all instances to the router script running on a local machine, simplifying SSH access without exposing instances to the public internet.</p>
<p><strong>Routing logic:</strong> At each scheduled interval, the script queries Electricity Maps for current carbon intensity in each region, picks the lowest, SSHs into that instance and kicks off training. No complex orchestration — just <code>python train_lora_cloud.py --r X --alpha Y --lr Z</code> executed remotely.</p>
<p>The script waits for each job to complete (~45 minutes), then waits 2 hours before the next submission. This gives roughly 2.75-hour intervals between job starts, allowing us to sample different times of day across all three grids.</p>
<h3>The Infrastructure</h3>
<p><strong>Router script (runs locally in our California lab):</strong></p>
<pre><code class="hljs language-python"><span class="hljs-keyword">def</span> <span class="hljs-title function_">pick_cleanest_region</span>():
    <span class="hljs-string">"""Query Electricity Maps, return cleanest region."""</span>
    intensities = {}
    <span class="hljs-keyword">for</span> region, config <span class="hljs-keyword">in</span> REGIONS.items():
        response = requests.get(
            <span class="hljs-string">"https://api.electricitymap.org/v3/carbon-intensity/latest"</span>,
            params={<span class="hljs-string">"zone"</span>: config[<span class="hljs-string">"zone"</span>]},
            headers={<span class="hljs-string">"auth-token"</span>: ELECTRICITY_MAPS_TOKEN}
        )
        intensities[region] = response.json()[<span class="hljs-string">"carbonIntensity"</span>]
    
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">min</span>(intensities, key=intensities.get), intensities

<span class="hljs-keyword">def</span> <span class="hljs-title function_">submit_job_ssh</span>(<span class="hljs-params">region, config, intensities</span>):
    <span class="hljs-string">"""SSH into region and kick off training."""</span>
    ip = REGIONS[region][<span class="hljs-string">"ip"</span>]  <span class="hljs-comment"># Tailscale IP</span>
    
    remote_cmd = (
        <span class="hljs-string">f"CARBON_REGION=<span class="hljs-subst">{region}</span> "</span>
        <span class="hljs-string">f"CARBON_INTENSITY=<span class="hljs-subst">{intensities[region]}</span> "</span>
        <span class="hljs-string">f"python3 train_lora_cloud.py "</span>
        <span class="hljs-string">f"--r <span class="hljs-subst">{config[<span class="hljs-string">'r'</span>]}</span> --alpha <span class="hljs-subst">{config[<span class="hljs-string">'alpha'</span>]}</span> "</span>
        <span class="hljs-string">f"--lr <span class="hljs-subst">{config[<span class="hljs-string">'lr'</span>]}</span> --dropout <span class="hljs-subst">{config[<span class="hljs-string">'dropout'</span>]}</span>"</span>
    )
    
    subprocess.run([
        <span class="hljs-string">"ssh"</span>, <span class="hljs-string">"-i"</span>, SSH_KEY_PATH, <span class="hljs-string">f"root@<span class="hljs-subst">{ip}</span>"</span>, remote_cmd
    ])
</code></pre>
<p>The entire "routing layer" is a few hundred lines of Python.</p>
<h3>The Submission Schedule</h3>
<p>We ran 21 jobs over approximately 2.5 days. Each job trains the same Qwen2.5-Coder-7B model with LoRA, using different hyperparameter configurations from a predefined sweep (varying rank, alpha, learning rate and dropout).</p>
<p>The jobs weren't identical — we varied hyperparameters across the sweep to make the training genuinely useful:</p>
<table>
<thead>
<tr>
<th>Parameter</th>
<th>Values Tested</th>
</tr>
</thead>
<tbody>
<tr>
<td>Rank (r)</td>
<td>16, 32</td>
</tr>
<tr>
<td>Alpha (α)</td>
<td>32, 64, 128</td>
</tr>
<tr>
<td>Learning Rate</td>
<td>1e-4, 5e-5, 1e-5</td>
</tr>
<tr>
<td>Dropout</td>
<td>0.05, 0.1, 0.15</td>
</tr>
</tbody>
</table>
<p>Each experiment trains Qwen2.5-Coder-7B on 5,000 samples from the HelpSteer2 dataset. Training time: roughly 0.76 hours per job on 4090 GPUs.</p>
<h3>Results</h3>
<h4>Where Did Jobs Actually Run?</h4>
<p>Of the 21 jobs submitted over ~55 hours:</p>
<ul>
<li><strong>Norway</strong>: 21 jobs (100%)</li>
<li><strong>Quebec</strong>: 0 jobs (0%)</li>
<li><strong>Ohio</strong>: 0 jobs (0%)</li>
</ul>
<p><em>[Was planning to have a visualization here but... umm. Norway ate the whole pie! Can you imagine a circle?]</em></p>
<p><strong>Every. Single. Job.</strong> went to Norway.</p>
<p>This wasn't quite what we expected. We anticipated some distribution — Quebec catching jobs during Norway's peaks, maybe Ohio winning the odd mid-day window. Instead, Norway's hydro-dominated grid was so consistently clean (33-39 gCO2/kWh) that it won every routing decision by a wide margin.</p>
<p>Quebec's hydro grid is objectively clean (40-63 gCO2/kWh, avg 51), but Norway's was cleaner. Ohio's fossil-heavy grid (472-580 gCO2/kWh, avg 523) never came close to Norway's baseline.</p>
<p><strong>What this teaches us:</strong> Spatial shifting doesn't require sophisticated runtime optimization. The cleanest region is often <em>so much cleaner</em> that dynamic balancing barely matters. Just pick Norway (or Quebec or Pacific Northwest) instead of Ohio/Virginia and you're getting at least 80% of the carbon saving benefits.</p>
<h4>Carbon Intensity Comparison</h4>
<table>
<thead>
<tr>
<th>Metric</th>
<th>Carbon-Routed (Norway)</th>
<th>Ohio Baseline</th>
<th>Difference</th>
</tr>
</thead>
<tbody>
<tr>
<td>Avg Intensity</td>
<td>35 gCO2/kWh</td>
<td>523 gCO2/kWh</td>
<td>-93%</td>
</tr>
<tr>
<td>Total Emissions</td>
<td>0.21 kgCO2</td>
<td>3.09 kgCO2</td>
<td>-93%</td>
</tr>
<tr>
<td>Total Energy</td>
<td>5.9 kWh</td>
<td>5.9 kWh</td>
<td>~same</td>
</tr>
</tbody>
</table>
<p>The energy consumption is essentially identical — we're doing the same computational work either way. The difference is purely in <em>where</em> that energy came from.</p>
<h4>The Counterfactual: What If We'd Just Used Ohio?</h4>
<p>The real-world baseline is Ohio/Virginia, because that's "where my team runs things." To establish this, we calculated what emissions would have been if all 21 jobs had run in Ohio at the times they were submitted and run, instead, in Norway.</p>
<p>Ohio's grid averaged 523 gCO2/kWh during our experiment window, while our routed jobs (all Norway) averaged 35 gCO2/kWh — a <strong>93% reduction</strong> from a single routing decision: "use Norway instead of Ohio."</p>
<p>To put it another way: Ohio's grid was nearly <strong>15x dirtier</strong> than Norway's throughout our experiment. Even Ohio's best hour (472 gCO2/kWh) was over 12x worse than Norway's worst (39 gCO2/kWh).</p>
<h4>Time-of-Day Patterns</h4>
<p>The pattern was remarkably stable:</p>
<ul>
<li><strong>Norway</strong>: Consistently 33-39 gCO2/kWh across all hours. Hydro-dominated grids don't vary much with time of day.</li>
<li><strong>Quebec</strong>: Ranged 40-63 gCO2/kWh. Also hydro-heavy, also stable, just slightly higher baseline.</li>
<li><strong>Ohio</strong>: Ranged 472-580 gCO2/kWh. Even Ohio's "best" hours couldn't compete with Norway's "worst" hours.</li>
</ul>
<p><strong>The key insight:</strong> When one grid is fundamentally cleaner by 15x, temporal variations don't matter.</p>
<h3>What We Learned</h3>
<h4>The Simplicity Thesis: The 80/20 of Carbon Reduction</h4>
<p>The headline result — 93% carbon reduction — exceeds what many simulations predicted. But the more important finding is <em>how</em> we achieved it: not through sophisticated dynamic optimization, but through a single decision: "use Norway instead of Ohio."</p>
<p>Norway won all 21 routing decisions because it's fundamentally cleaner (33-39 gCO2/kWh) than the alternatives. Quebec is clean (~51), but not <em>as</em> clean. Ohio is dirty (~523) and no amount of temporal variation brings it close to Norway's baseline.</p>
<p>The 93% number isn't a discovery; anyone who's looked at Electricity Maps for 10 minutes could predict Norway beats Ohio. The finding is that <strong>93% is achievable with very simple tools and minimal setup friction</strong>. The experiment proved you can actually route to Norway, not just that you theoretically should.</p>
<p><strong>This is an 80/20 leverage point.</strong> The actionable advice isn't "build a complex multi-region orchestration system." It's "check Electricity Maps for your available cloud regions, pick the cleanest one as your new default, done."</p>
<h4>What Actually May Require Complexity</h4>
<p>Region-to-grid mapping can take a bit of homework. Cloud regions and GPU rental locations don't always map cleanly to electrical grid zones. In Ohio, exact location determines whether you're on PJM or MISO. "Norway" on Vast.ai could technically mean different parts of the Norwegian grid, though Norway's grid is remarkably homogeneous due to hydro dominance. Ultimately, we spent as much time verifying our instances were in the right grid zones as we did building the routing logic.</p>
<p>When using public cloud providers, Electricity Maps API will even <a href="https://app.electricitymaps.com/developer-hub/api/reference#data-centers">do that mapping for you</a>.</p>
<h4>Spatial vs. Temporal: Different Problems, Different Solutions</h4>
<p><strong>Spatial shifting can be about defaults.</strong> For many workloads, "just always use Norway" is enough. The clean region wins so consistently that dynamic routing adds complexity without much benefit.</p>
<p><strong>But spatial shifting has thorny constraints:</strong></p>
<ul>
<li>Data residency and sovereignty (GDPR, healthcare, financial regulations)</li>
<li>Data transfer costs and latency (moving TB-scale datasets between regions)</li>
<li>Regional availability and quota limits</li>
</ul>
<p><strong>Temporal shifting avoids most of these.</strong> Running the same job at 2pm instead of 2am doesn't move data across borders or incur egress fees. For many organizations, temporal shifting within a single region may be more practical than spatial shifting across borders.</p>
<p><strong>The layers stack.</strong> The real opportunity is combining a few:</p>
<ol>
<li>Pick the cleanest region you <em>can</em> use (spatial)</li>
<li>Within that region, run jobs during cleanest hours (temporal; ex: Compute Gardener)</li>
<li>Use infrastructure sleep strategies (ex: KubeGreen) to shut down idle resources</li>
<li>Use carbon-aware autoscaling (ex: KEDA with carbon signals) for variable loads</li>
<li>Application layer optimization</li>
</ol>
<p>Each layer compounds the benefit.</p>
<h4>Versus the Simulations</h4>
<p>Academic papers often report 20-40% potential savings from spatial shifting. Our 93% result significantly exceeds that range because we deliberately chose a stark contrast: one of the cleanest grids on Earth (Norway hydro) versus a dirty, fossil-heavy grid (Ohio coal/gas). Simulations typically model more moderate contrasts or average across diverse workloads.</p>
<p>We're not claiming 93% is universally achievable — it's not. But using an extreme example makes the point obvious: the leverage exists and the workflow to access it is surprisingly simple. The carbon cost of proving this? About 0.21 kgCO2 for the Norway runs — less than driving 2 miles. The difference from running this experiment versus just simulating it is negligible; the difference between running in Norway versus Ohio for real workloads at scale is enormous.</p>
<h4>Where Compute Gardener Fits</h4>
<p>This experiment taught us that <strong>routing and scheduling are different problems</strong>:</p>
<p><strong>Routing (which region)</strong>: Can often be a pre-deployment decision. "Should this job run in Ohio or Norway?" This can be as simple as a policy: "all deferrable ML training goes to the generally cleanest grid."</p>
<p><strong>Scheduling (when to run)</strong>: Can be a runtime decision within a cluster. This is where Compute Gardener excels. For deferrable batch workloads in Kubernetes, Compute Gardener (CG) provides carbon intensity thresholds per pod, maximum delay enforcement, energy budget tracking and price-aware scheduling.</p>
<p><strong>Why temporal shifting still matters:</strong> Even in a dirty grid like Ohio, intensity varies 472-580 gCO2/kWh throughout the day. A job scheduled to run during midday (472) instead of overnight (580) achieves ~19% reduction — without crossing borders, moving data or dealing with compliance headaches.</p>
<p><strong>The complete picture</strong> for carbon-aware ML training:</p>
<ol>
<li><strong>Spatial layer</strong>: Pick the cleanest region your constraints allow</li>
<li><strong>Temporal layer</strong>: Within that region, defer jobs to cleaner hours</li>
<li><strong>Infrastructure efficiency</strong>: Sleep idle resources, scale based on carbon signals</li>
<li><strong>Application efficiency</strong>: Make the work itself more efficient</li>
</ol>
<p>For organizations that can't use Norway's grid due to data residency, temporal shifting becomes even more critical.</p>
<h4>What About US-Only Spatial Shifting?</h4>
<p>An interesting middle ground we didn't test: routing between US regions only. This avoids most data residency concerns while still leveraging grid variation (Pacific Northwest: 80-150, Ohio/Virginia: 400-600, Texas: 200-500).</p>
<p>Does spatial shifting <em>within America</em> behave the same way? Set-it-and-forget-it? Or is that an environment when the "dynamic optimization matters" thesis from academic papers rings true? Our hypothesis: somewhere in between, but likely still favoring "just default to Quebec or Pacific Northwest" for most jobs.</p>
<h3>Limitations and Honest Caveats</h3>
<p>Our experiment showed dramatic results (93% carbon reduction), but it's important to understand what this doesn't capture and when the "just use Norway" heuristic breaks down.</p>
<h4>Data Transfer Costs and Latency</h4>
<p>We assume training data magically appears wherever we need it. In reality, moving large datasets between regions costs money and adds latency. For our 5,000-sample dataset (~few hundred MB) and ~15GB model, this was negligible. For TB-scale datasets, it's a real constraint that fundamentally changes the economics.</p>
<h4>Data Sovereignty and Compliance</h4>
<p>Many organizations face legal requirements: GDPR restricts where EU citizen's data can be processed, healthcare data often can't leave national boundaries, financial services may prohibit cross-border processing. Our "just use Norway" advice only works if you legally <em>can</em> use Norway. For many orgs, US-only or EU-only spatial shifting is the only option.</p>
<h4>No Temporal Shifting in This Experiment</h4>
<p>We deliberately excluded temporal shifting to isolate spatial effects. Jobs ran immediately in whichever region was selected. Combining spatial + temporal could compound savings (95%+ total reduction), but adds coordination complexity.</p>
<h4>Measurement Uncertainty</h4>
<p>Unlike Parts 1 and 2, we don't have actual power meter data. We're using observed GPU utilization (~320W at P2 power level) plus an estimate for system overhead (~50W). Vast.ai instance locations aren't usually as precisely defined as hyperscaler regions. Our carbon intensity numbers are real (from Electricity Maps API), but total emissions calculations have ~10-20% uncertainty.</p>
<p>That said, even with 20% measurement error in both directions, the fundamental result holds: Norway's grid (33-39 gCO2/kWh) is so much cleaner than Ohio's (472-580 gCO2/kWh) that the magnitude of the difference isn't in question, only the precise percentage.</p>
<h3>What's Next</h3>
<p><strong>For Compute Gardener's roadmap</strong>:</p>
<ul>
<li><strong>Temporal optimization within regions</strong>: CG already handles this for Kubernetes workloads</li>
<li><strong>Integration with spatial routing policies</strong>: Organizations can set "use Pacific Northwest for batch jobs" policies, CG optimizes <em>when</em> within that region</li>
<li><strong>Hybrid on-prem + cloud</strong>: If you have local GPUs <em>and</em> cloud access, CG can help you weigh more nuanced trade-offs (ex: run now locally or defer and burst to cloud during clean hours).</li>
</ul>
<p>We're not waiting for perfect solutions to start reducing emissions. The necessary tools exist today.</p>
<h3>Reproducibility</h3>
<p>All code, logs and data from this experiment are available in our <a href="https://github.com/elevated-systems/compute-gardener-scheduler/tree/main/docs/carbon-aware-ml-experiments/cloud-pt3">GitHub repo</a>.</p>
<p>To run your own spatial shifting experiment:</p>
<ol>
<li>Rent GPU instances in multiple regions (we used Vast.ai RTX 4090s)</li>
<li>Set up Tailscale or similar VPN for easy instance access</li>
<li>Install Python ML dependencies on each instance</li>
<li>Get an Electricity Maps API key (free tier works for experimentation)</li>
<li>Configure the routing script with your instance IPs and grid zones</li>
<li>Run: <code>python spatial_router.py --run-experiment</code></li>
</ol>
<p>No Kubernetes required. Total compute cost: approximately $50 over 2.5 days. Could be much less with a more active provisioning strategy (we had all nodes reserved).</p>
<hr>
<h3>Is This Right for Your Workloads?</h3>
<p>Every discussion of carbon-aware computing comes with the same caveat: <em>results depend heavily on your specific usage profile</em>. Your default region, your job duration, your flexibility constraints; they do all matter.</p>
<p>The experiments in this series demonstrate what's possible under specific conditions. Of course, your conditions are different. Maybe you're already multi-region and spatial routing is low-hanging fruit. Maybe your workloads are latency-sensitive and can't move. The only way to know is to look at your actual usage patterns and do the analysis.</p>
<p>Whether you're exploring carbon-aware scheduling for the first time or trying to quantify the opportunity for your specific infrastructure, we offer consulting engagements designed to answer: <em>what would this look like for us and our wacky X stack?</em></p>
<p><strong><a href="/contact">Let's figure out your carbon optimization opportunity →</a></strong></p>
<hr>
<p><em><a href="https://github.com/elevated-systems/compute-gardener-scheduler">Compute Gardener</a> is an open-source project focused on making carbon-aware computing practical, not just theoretical. Join us in moving sustainable computing from white papers to production.</em></p>]]></content:encoded>
            <enclosure url="https://www.compute-gardener.com/blog/images/legoSunnyRacks.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[The Parts They Don't Tell You About Founder Life (Though You Wouldn't Listen To Them Anyway)]]></title>
            <link>https://www.compute-gardener.com/resources/blog/founder-lessons</link>
            <guid isPermaLink="false">https://www.compute-gardener.com/resources/blog/founder-lessons</guid>
            <pubDate>Tue, 25 Nov 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[Let's get real about delusional entrepreneurship.]]></description>
            <content:encoded><![CDATA[<p>I knew, theoretically, what I was signing up for when I left my job to start Compute Gardener. I'd read the articles, heard the war stories, nodded along to the podcast interviews where founders talked about the emotional rollercoaster. I understood the statistics. I knew most startups fail.</p>
<p>But here's the thing about theoretical knowledge: it lives in your head, where it can't really hurt you, at least not emotionally. The possibility seems safe enough at first consideration. Comfortable, even. You can sit in a company cafeteria, sipping free coffee, thinking about all that flexibility and upside, and the theoretical risks feel... manageable. Abstract. Like something that happens to other people.</p>
<p>Months into this journey, I'm constantly being reminded that <em>imagining</em> these realities is a completely different beast than <em>experiencing</em> them.</p>
<p>So this post is my attempt to put some of those feelings into words; not because I have answers, but because I suspect I'm not alone in being surprised by how these things actually hit.</p>
<h3>The "Right Thing" Trap</h3>
<p>Every morning, I face a version of the same question: Am I doing the right thing today?</p>
<p>Not in a moral or philosophical sense. But in a brutally practical one: Should I be writing code or should I be reaching out to potential users? Should I refine the product or should I be building community? Should I dig into that technical problem I find fascinating or should I force myself to do the marketing work that makes my skin crawl?</p>
<p>The trap is this: I can easily convince myself that what I <em>want</em> to be doing is what I <em>should</em> be doing. I'm technical. I love solving technical problems. It feels productive. It feels like progress. And maybe it is! Or maybe I'm just hiding in my comfort zone while the things that actually matter (the uncomfortable work of putting myself out there, of building relationships, of doing marketing as a decidedly non-marketing person) languish on my todo list.</p>
<p>Am I sure I'm laying the groundwork for innovative projects to come or am I simply <a href="https://cupofcode.blog/yak-shaving/">yak shaving</a> our lab setup? Am I REALLY sure about that?</p>
<p>Before venturing out, I knew these things would be challenging. It turns out they're challenging not because the tasks themselves are insurmountable, but instead because every single day you have to choose discomfort over comfort, uncertainty over certainty, vulnerability over control. You have to do the things you're worst at first, the things that feel awkward and forced, knowing full well it might not even matter.</p>
<p>And here's what makes it worse: you're never quite sure you're making the right call. Maybe the technical work <em>is</em> the priority right now. Maybe I <em>am</em> overthinking the marketing stuff. Maybe, maybe, maybe.</p>
<p>The theoretical knowledge that "founders need to do uncomfortable things" does not prepare you for the daily, grinding reality of doing them anyway while second-guessing yourself the entire damn time.</p>
<h3>The Impact Paradox</h3>
<p>Let's talk about the math that doesn't quite add up, the calculation we all make when we decide to start something.</p>
<p>At a large company, there's a floor and a ceiling on your impact. You're probably not going to directly change the world from inside Google or Microsoft, but you're also not going to have <em>zero</em> impact. You'll ship features, help colleagues, contribute to products that reach millions of people. The impact is real, if bounded.</p>
<p>But that's not why we become entrepreneurs. We do it because we want to break through that ceiling. We want the upside: the possibility of having <em>massive</em> impact, of building something that genuinely changes how people work, of seeing our ideas actually matter in the world.</p>
<p>Of course, in reaching for that possibility, we've also removed the floor.</p>
<p>The most likely outcome of any startup isn't moderate success or even graceful failure. It's <em>zero impact</em>. Or close to it. You can pour years of your life into something, do everything "right," and still end up with a product nobody uses, a blog nobody reads, a company nobody's paying.</p>
<p>I knew this, statistically, before I started. Startups fail. Most ideas don't find product-market fit. That's just how it works. What I didn't fully appreciate was how this knowledge would <em>feel</em> in the middle of the journey. When you're months in, when you're questioning whether you've even identified the right metrics to track progress, when you're not sure if you're making traction or just moving in circles, the possibility of zero impact stops being a statistic and starts being a weight you carry.</p>
<p>The irony is that entrepreneurs are precisely the people drawn to situations where they can amplify their impact. We <em>want</em> the leverage and the possibility of outsized returns on our effort. But that same leverage cuts both ways. The structure that lets you 100x your impact also allows you to 0x it.</p>
<p>And we go in with eyes open! We tell ourselves we understand the risks. We probably even believe it.</p>
<p>But sitting in that Google cafeteria, contemplating the leap, imagining the freedom and flexibility and potential... I don't think I really <em>felt</em> what it would be like to worry that all of this might amount to nothing. That the conversations I'm having, the code I'm writing, the posts I'm publishing; all of it might just be noise that nobody hears.</p>
<p>Of course, there are silver linings. Learnings. Connections. Skills developed. These aren't nothing. But they also aren't the goal. The goal is <em>impact</em>. The goal is building something that matters.</p>
<h3>"But It Might Work for Us"</h3>
<p>There's an old <em>Arrested Development</em> bit where Tobias and Lindsay are talking about having an open relationship. They acknowledge that such relationships never work for anyone, people are only deluded into thinking they will. And then Tobias says, cheerfully: "But it might work for us."</p>
<p><img src="/blog/images/butItMightWorkForUs.png" alt="TobiasMeme"></p>
<p>I know I often feel like Tobias. And if you're the kind of person considering starting something, or in the middle of your own journey, you're probably thinking: "Sure, but this doesn't apply to me." You're different. Your idea is different. You'll do the uncomfortable work. You won't fall into the traps.</p>
<p>And you know what? Maybe you're right! Of course, many entrepreneurs do succeed. The statistics don't apply equally to everyone. Maybe you <em>are</em> the exception. I really hope you are.</p>
<p>But here's my warning, delivered with as much vulnerability and hard-earned wisdom as I can muster while maintaining <em>some</em> professional credibility: you probably won't believe you're in the trap until you're already caught in it. You may not realize you've been hiding in comfortable technical work until months have passed. You likely won't feel the weight of potential zero-impact until you realize it's already around your neck.</p>
<p>I'm not writing this to discourage you. Honestly, I don't believe anything I write could discourage the kind of person who I'm writing this for. If you're built for it, you're going to do it anyway, warnings be damned.</p>
<p>I'm saying it because maybe, just maybe, having someone mention these feelings makes them slightly less isolating when (not if) you encounter them. Maybe knowing that the gap between theoretical understanding and lived experience is shared by others makes the surprise of it sting a tiny bit little less.</p>
<h3>Where I Am Now</h3>
<p>I'm still figuring this out. I don't have a neat conclusion or a five-point action plan. I'm not always sure I'm doing the right things on any given day. I don't know if Compute Gardener will gain the traction it needs to survive, let alone thrive. I don't know if I'm measuring the right metrics or if I'm even asking myself the right questions.</p>
<p>What I <em>am</em> doing is sitting in the discomfort. Doing the marketing work even though it feels painfully awkward. Building in public even though it's vulnerable. Writing posts like this one even though it would be easier to just stick to technical content.</p>
<p>And I'm trying to remember that the people who succeed at this aren't the ones who avoid these feelings. They're the ones who feel them and keep going anyway.</p>
<p>If you're in this with me, whether you're months ahead or months behind: I see you. This is harder than they told us. But even if we heard the warnings, we know we were probably going to do it anyway.</p>
<p>Because despite everything I've written here, despite the uncertainty and the discomfort and the very real possibility that this might not work out... I still think it just might work for us!</p>
<hr>
<p><em>Compute Gardener is a project aimed at simplifying carbon-aware computing in Kubernetes. If you want to follow along with this journey; the technical wins, the strategic pivots, the occasional existential crisis... you can find details about the project on our <a href="https://www.compute-gardener.com">website</a>, <a href="https://github.com/elevated-systems/compute-gardener-scheduler">github repo</a> or reach out directly (<a href="mailto:dave@elevated-systems.com">dave@elevated-systems.com</a>). I'm always happy to compare notes with fellow founders, especially over coffee. The kind we pay for ourselves now.</em></p>]]></content:encoded>
            <enclosure url="https://www.compute-gardener.com/blog/images/legoBeforeBuild2.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[Making ML Training Carbon-Aware with Compute Gardener (Part 2)]]></title>
            <link>https://www.compute-gardener.com/resources/blog/ml-training-carbon-aware-pt2</link>
            <guid isPermaLink="false">https://www.compute-gardener.com/resources/blog/ml-training-carbon-aware-pt2</guid>
            <pubDate>Mon, 03 Nov 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[Part 2 details how Compute Gardener can limit emissions of KubeRay managed LoRA training, with intelligent scheduling.]]></description>
            <content:encoded><![CDATA[<p><em>How we reduced emissions by 40% during a LoRA hyperparameter search with a flexible, tiered and carbon aware strategy</em></p>
<hr>
<h3>Continuing from Part 1</h3>
<p>In <a href="https://www.compute-gardener.com/resources/blog/ml-training-carbon-aware-pt1">Part 1</a>, we demonstrated how Compute Gardener (CG) could reduce carbon emissions by ~30% for simple, recurring ML training jobs. The setup was straight-forward: daily ResNet50 training jobs, shifted to cleaner energy windows.</p>
<p>But that raised important questions that have come up in related discussion:</p>
<blockquote>
<p>If everyone delays to 2pm, haven't we just moved the problem?</p>
</blockquote>
<blockquote>
<p>This works for toy examples, but what about real ML workflows?</p>
</blockquote>
<p>These are fair questions. So for Part 2, let's build a more complex and realistic scenario: <strong>hyperparameter optimization for LLM fine-tuning</strong> using Ray on Kubernetes. And let's do it with intelligent, carbon-aware scheduling that distributes load rather than creating new stampedes.</p>
<h3>Real-World Scenario: LLM Fine-Tuning Hyperparameter Search</h3>
<p>Qwen2.5-Coder was one of the more pleasantly surprising open-weights models I've worked heavily with in the past year. This model made me realize that open models aren't more than a year (probably more like just 6 months) behind the capabilities of closed frontier models (of similar sizes).</p>
<p>Today, Qwen2.5-Coder is not the "latest and greatest" of open models BUT it does hold a soft spot in my heart. And perhaps more importantly, the newer Qwen3-Coder models are all too large to train on immediately available GPUs (even with some quantization).</p>
<p>So, we decided to fine-tune <a href="https://huggingface.co/Qwen/Qwen2.5-Coder-7B-Instruct">Qwen2.5-Coder-7B</a> to create a specialized coding assistant. Like most ML projects, we didn't know the optimal training configuration upfront, so we needed to test multiple LoRA (Low-Rank Adaptation) hyperparameter combinations:</p>
<ul>
<li><strong>Rank (r)</strong>: [16, 32] — size of adapter (r=32 is the practical limit for 7B models at bfloat16 on a 24GB GPU)</li>
<li><strong>Alpha (a)</strong>: [32, 64, 128] — scaling factor for LoRA weights</li>
<li><strong>Learning rate (lr)</strong>: [1e-4, 5e-5, 1e-5] — how aggressively to update weights</li>
<li><strong>Dropout (d)</strong>: [0.05, 0.1, 0.15] — regularization to prevent overfitting</li>
</ul>
<p>A full factorial sweep would be 54 combinations (2 × 3 × 3 × 3), too many for this experiment. Instead, we designed a <strong>targeted sample of 21 experiments</strong> that systematically explore the hyperparameter space:</p>
<ul>
<li><strong>1 baseline and 7 related variations</strong> (Tier 1, r=16): Testing learning rates, alpha values and dropout values around the proven baseline rank</li>
<li><strong>4 promising directions</strong> (Tier 2, r=32): Stepping up model capacity with standard hyperparameters</li>
<li><strong>9 experimental long shots</strong> (Tier 3, r=32): Aggressive/unconventional hyperparameter combinations (high alpha, extreme dropout, very conservative learning rates)</li>
</ul>
<p><strong>This is a hyperparameter sweep</strong>; training the same model architecture multiple times with different configuration settings, then comparing results to find the best combination. It's one of the most common workflows in ML research and production model development.</p>
<p><strong>Note on scope</strong>: The following approach works best for batch/deferrable workloads (ex: hyperparameter searches, model evaluations, periodic retraining, research experiments). Production inference requires different carbon-awareness strategies like geographic load balancing and efficient model architectures.</p>
<h4>Training Dataset</h4>
<p>We're fine-tuning on <strong>nvidia/HelpSteer2</strong>, an open-source dataset of 21k prompt-response pairs with human annotations for helpfulness, correctness, coherence, complexity, and verbosity. It's NVIDIA's recommended dataset for training helpful assistants.</p>
<p>For this experiment, we use <strong>5,000 samples</strong> split 80/20 into training (4,000) and validation (1,000). This keeps training times reasonable while providing enough data to demonstrate the carbon-aware scheduling approach and compare hyperparameter configurations.</p>
<h4>Setup and Timeline</h4>
<p>Training times vary by rank due to the increased LoRA parameter count:</p>
<ul>
<li>r=16: ~1.4 hours (8 experiments)</li>
<li>r=32: ~1.6 hours (13 experiments)</li>
</ul>
<p>This is a total of ~32 GPU hours.</p>
<p>We used two 24GB GPUs (one NVIDIA RTX 3090, one NVIDIA RTX A5000) on separate nodes in our Kubernetes cluster. The experiment ran for just over 2 days (51.3 hours), 28-30Oct2025. The consumer RTX 3090 is ~5% faster at completing these jobs but uses ~80% more energy compared to the enterprise A5000. This presents a trade-off in carbon-aware scheduling: slightly faster completion vs much lower energy consumption.</p>
<h4>The Traditional Approach: Random Submission</h4>
<p>The typical workflow looks like this:</p>
<pre><code class="hljs language-bash"><span class="hljs-comment"># Monday morning: Try a baseline</span>
kubectl apply -f rayjob-r16-a32-lr1e4.yaml

<span class="hljs-comment"># Monday afternoon: Results look good, try variations</span>
kubectl apply -f rayjob-r16-a64-lr5e5.yaml
kubectl apply -f rayjob-r32-a32-lr1e4.yaml

<span class="hljs-comment"># Tuesday morning: More experiments based on what worked</span>
kubectl apply -f rayjob-r32-a64-lr5e5.yaml
<span class="hljs-comment"># ... and so on</span>
</code></pre>
<p><strong>Predictable Result</strong>: Jobs run whenever submitted and resources are available, scattered somewhat randomly across the carbon intensity spectrum. Some at 350 gCO2eq/kWh (peak intensity hours), others at 120 gCO2eq/kWh (solar valleys).</p>
<p><strong>Note</strong>: For the remainder of this article, we will simplify the unit as gCO2/kWh. But in all places, (k)gCO2eq or gCO2eq/kWh are technically accurate.</p>
<h3>The Naive Carbon-Aware Approach (And Why It Fails)</h3>
<p>Our first instinct was simple: "Just delay everything until carbon intensity is low!"</p>
<p><strong>The problem</strong>: With limited GPU resources (2 GPUs) and many experiments, forcing everything to wait for the absolute lowest carbon window creates a stampede. When conditions are finally met (or max-delay expires), all jobs compete for just 2 GPUs. The first few might run during optimal windows, but the tail-end jobs likely don't start until carbon intensity climbs back to 250+ gCO2/kWh.</p>
<p><strong>The lesson</strong>: We need to distribute load across multiple "good enough" windows rather than clustering everything at the absolute minimum.</p>
<h3>Better Solution: A Tiered Strategy</h3>
<p>Not all experiments are created equal. Some configurations need fast feedback (baseline adjacent validations), while others are speculative and can wait for optimal conditions (long shots).</p>
<p>Our strategy: <strong>Distribute experiments across multiple "good enough" carbon thresholds using three tiers</strong>, each with different urgency profiles:</p>
<ul>
<li><strong>Tier 1</strong> (225 gCO2/kWh, 24h max delay): Baseline adjacent variations with r=16 for fast feedback</li>
<li><strong>Tier 2</strong> (175 gCO2/kWh, 48h max delay): Promising r=32 configurations with standard hyperparameters</li>
<li><strong>Tier 3</strong> (125 gCO2/kWh, 96h max delay): Experimental r=32 long shots with aggressive hyperparameters</li>
</ul>
<p>This is essentially a <strong>priority queue pattern with carbon constraints as the primary gate</strong>.</p>
<p>California's grid (CalISO) has a clear daily pattern: carbon intensity is highest overnight and early morning (300-400 gCO2/kWh), then drops dramatically during the midday solar peak (typically 100-200 gCO2/kWh around noon to 2pm), before climbing again in the evening as solar generation fades.</p>
<p>Our three-tier strategy doesn't try to hit the single "perfect" window throughout the day. Instead, it solves two practical problems when you have <strong>limited GPU resources</strong> (2 GPUs) and <strong>many experiments</strong> (21 jobs):</p>
<h4>Preventing the Stampede</h4>
<p>If all 21 experiments had the same low threshold (say, 100 gCO2/kWh), they would all wait behind CG's carbon gate until either:</p>
<ol>
<li>Carbon intensity drops below 100 OR</li>
<li>They hit their max delay (say, 24h) and CG stops blocking them</li>
</ol>
<p>But after CG releases the jobs, they compete for just 2 GPUs through normal Kubernetes resource scheduling. The initial few jobs can run immediately during optimal conditions. However, the deeply queued jobs likely won't be able to execute until a less optimal time. In the worst case, such a stampede can make carbon intensity worse for many of the jobs.</p>
<p>But by using <strong>225/175/125 gCO2/kWh</strong> thresholds, we'll create a natural flow:</p>
<ul>
<li><strong>Tier 1 jobs</strong> (threshold 225, 8 jobs) start running in early morning as intensity drops below 225</li>
<li><strong>Tier 2 jobs</strong> (threshold 175, 4 jobs) join in late morning when it dips below 175</li>
<li><strong>Tier 3 jobs</strong> (threshold 125, 9 jobs) run during the deepest part of the solar valley in the early afternoon</li>
</ul>
<p>This spreads the 21-job workload across a handful of low-carbon periods rather than clustering everything at the absolute minimum.</p>
<h4>Intelligent GPU Allocation</h4>
<p>This is the <strong>priority queue pattern with carbon constraints</strong>. When a GPU finishes one experiment and becomes available, the scheduler picks the next job that:</p>
<ol>
<li><strong>Meets its carbon threshold</strong> - current intensity is low enough</li>
<li><strong>Has the highest priority</strong> - Tier 1 > Tier 2 > Tier 3 within acceptable jobs</li>
<li><strong>Has been waiting longest</strong> - within that tier</li>
</ol>
<p><strong>The separation of concerns</strong> makes this clean:</p>
<ul>
<li><strong>Ray</strong>: Manages experiment orchestration and dependencies</li>
<li><strong>Kubernetes</strong>: Allocates GPU resources and handles pod lifecycle</li>
<li><strong>Compute Gardener</strong>: Gates scheduling based on carbon intensity threshold</li>
<li><strong>Result</strong>: Each layer handles what it's best at</li>
</ul>
<p><strong>The key insight</strong>: We're not optimizing to "run everything at minimum carbon intensity." Instead we're optimizing with a blended consideration, "distribute the queue intelligently so experiments run when carbon is acceptably low AND GPU resources are available."</p>
<h3>Implementation: Automating Tier Assignment</h3>
<p>Rather than manually categorizing each experiment, we automated tier assignment based on hyperparameter characteristics, using a python script.</p>
<p><strong>Note</strong>: Please checkout this post's supporting materials in our <a href="https://github.com/elevated-systems/compute-gardener-scheduler/tree/8a33a3e3d00d6a90152ee671a664fbccce5c5f56/docs/carbon-aware-ml-experiments/lora-pt2">Github repo</a>.</p>
<h4>The workflow</h4>
<pre><code class="hljs language-bash"><span class="hljs-comment"># 1. Generate targeted sample of 21 manifests with carbon tiers</span>
python generate_sweep.py --output-dir sweep_manifests --core-subset
<span class="hljs-comment"># Output: 21 YAML files with intelligent tier assignments and annotations</span>

<span class="hljs-comment"># 2. Submit to Kubernetes (can submit all at once, individually or by tier)</span>
kubectl apply -f sweep_manifests/

<span class="hljs-comment"># 3. Ray coordinates job execution, CG handles carbon-aware scheduling</span>
<span class="hljs-comment"># No further intervention needed - jobs run when conditions are favorable</span>
</code></pre>
<p><strong>What happens under the hood:</strong></p>
<ol>
<li>Ray creates pods ("head" and GPU workers) for each training job</li>
<li>Compute Gardener scheduler evaluates each pod:
<ul>
<li>Checks current carbon intensity via Electricity Maps API</li>
<li>Compares against pod's threshold annotation</li>
<li>If intensity is acceptable, schedules immediately</li>
<li>Otherwise, delays and re-evaluates periodically</li>
</ul>
</li>
<li>Jobs complete, then save models and metrics to persistent storage</li>
<li>Repeat until all experiments finish</li>
</ol>
<h3>Carbon Intelligent Scheduling vs Simple Batch Submission</h3>
<p>We ran all 21 experiments from <strong>October 28-30, 2025</strong>, capturing actual carbon intensity data for the California grid (CalISO) via Electricity Maps API. Here's what we found:</p>
<h4>Three-Tier Strategy (Our Approach)</h4>
<ul>
<li><strong>Average carbon intensity</strong>: 142 gCO2/kWh</li>
<li><strong>Total emissions</strong>: 1.81 kgCO2</li>
<li><strong>Total energy consumption</strong>: 12.2 kWh across all 21 experiments</li>
<li><strong>Wall-clock completion time</strong>: ~50.3 hours</li>
<li><strong>Distribution</strong>: Naturally spread across low-carbon periods over 2 days</li>
<li><strong>Research velocity</strong>: Maintained — Tier 1 baseline results available within the first day</li>
</ul>
<h4>The Alternative Universe: No Carbon Awareness</h4>
<p>To estimate relative impact, we calculated what would have happened if the same 21 experiments had run immediately upon submission, executing two at a time continuously through the first night:</p>
<ul>
<li><strong>Average carbon intensity</strong>: 226 gCO2/kWh (62.7% <strong>higher</strong> than our approach)</li>
<li><strong>Total emissions</strong>: 3.03 kgCO2 (67% <strong>higher</strong> than our approach)</li>
<li><strong>Total energy consumption</strong>: 12.2 kWh (same — same work done either way)</li>
<li><strong>Wall-clock completion time</strong>: ~16.2 hours (2 GPUs running continuously)</li>
<li><strong>Distribution</strong>: Heavy overnight execution during fossil-fuel heavy grid hours</li>
</ul>
<p><strong>Key insight</strong>: We achieved <strong>more than 40% carbon reduction</strong> by intelligently distributing experiments across cleaner time windows. The same computational work (12.2 kWh) produced dramatically different emissions based purely on <em>when</em> it ran.</p>
<h3>Assessing Training Quality</h3>
<p>After all experiments completed, we needed to determine which hyperparameter configuration produced the best model. This requires both quantitative metrics and qualitative assessment.</p>
<h4>Quantitative Metrics</h4>
<p>Each training run logged both the final training loss as well as the average validation loss.</p>
<p><strong>Validation loss</strong> (not training loss) is the primary quality metric. It measures how well the model generalizes to unseen data. Lower is better, but only to a point (too low can indicate overfitting).</p>
<p>We established <strong>rank=16, alpha=32, learning rate=1e-4, dropout=0.1</strong> as our baseline configuration (validation loss: 0.7899). Here are the top performers relative to that baseline:</p>
<p><strong>Top 5 configurations by validation loss:</strong></p>
<table>
<thead>
<tr>
<th>Top Finishers</th>
<th>rank</th>
<th>alpha</th>
<th>learning rate</th>
<th>dropout</th>
<th align="right">Val Loss</th>
<th align="right">Δ vs Baseline</th>
<th align="right">Carbon cost (gCO2)</th>
<th>Tier</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>32</td>
<td>128</td>
<td>1e-4</td>
<td>0.05</td>
<td align="right">0.6970</td>
<td align="right"><strong>-0.0929</strong></td>
<td align="right">51.4</td>
<td>3</td>
</tr>
<tr>
<td>2</td>
<td>32</td>
<td>128</td>
<td>1e-4</td>
<td>0.1</td>
<td align="right">0.7010</td>
<td align="right"><strong>-0.0889</strong></td>
<td align="right">94.5</td>
<td>3</td>
</tr>
<tr>
<td>3</td>
<td>32</td>
<td>128</td>
<td>1e-4</td>
<td>0.15</td>
<td align="right">0.7037</td>
<td align="right"><strong>-0.0862</strong></td>
<td align="right">56.1</td>
<td>3</td>
</tr>
<tr>
<td>4</td>
<td>16</td>
<td>128</td>
<td>1e-4</td>
<td>0.1</td>
<td align="right">0.7059</td>
<td align="right"><strong>-0.0840</strong></td>
<td align="right">90.8</td>
<td>1</td>
</tr>
<tr>
<td>5</td>
<td>16</td>
<td>64</td>
<td>1e-4</td>
<td>0.1</td>
<td align="right">0.7490</td>
<td align="right"><strong>-0.0409</strong></td>
<td align="right">70.3</td>
<td>1</td>
</tr>
<tr>
<td><strong>Baseline</strong></td>
<td>16</td>
<td>32</td>
<td>1e-4</td>
<td>0.1</td>
<td align="right">0.7899</td>
<td align="right">0.0000</td>
<td align="right">52.1</td>
<td>1</td>
</tr>
</tbody>
</table>
<p><strong>Interesting findings</strong>:</p>
<ul>
<li>The top 3 models all used <strong>alpha=128</strong> with <strong>r=32</strong>, achieving 9-12% improvement over baseline</li>
<li>Tier 3 experiments (the "long shots" designed to wait for optimal carbon windows) dominated the top results</li>
<li>Higher alpha values (128 vs 32) had more impact on performance than rank increases (r=32 vs r=16)</li>
</ul>
<h4>Qualitative Testing</h4>
<p>Metrics only tell part of the story. We also deployed the top 3 candidates with vLLM and tested them on real coding tasks:</p>
<pre><code class="hljs language-bash"><span class="hljs-comment"># Deploy top candidates for interactive testing</span>
kubectl apply -f vllm-deployment-r32-a128.yaml
kubectl port-forward svc/vllm-lora 8000:8000

<span class="hljs-comment"># Test with prompts</span>
curl http://localhost:8000/v1/chat/completions -d <span class="hljs-string">'{
  "model": "Qwen/Qwen2.5-Coder-7B-Instruct:qwen-lora-r32-a128",
  "messages": [{
    "role": "user",
    "content": "Write a Python function for binary search with edge case handling"
  }]
}'</span>
</code></pre>
<p><strong>What we evaluated:</strong></p>
<ul>
<li>Code correctness and handling of edge cases</li>
<li>Code style and readability</li>
<li>Ability to follow instructions and successfully use tools</li>
<li>Response to follow-up questions ("ex: what else can be improved in this codebase?")</li>
</ul>
<p><strong>The winner</strong>: rank=32, alpha=128, learning rate=1e-4, dropout=0.05; this configuration combined the best quantitative performance (lowest validation loss) with seemingly strong code and assistance quality. This was a Tier 3 experiment which waited for near-optimal carbon conditions.</p>
<h3>Recap</h3>
<ul>
<li>
<p><strong>40% carbon reduction is achievable with intelligent scheduling</strong>: By shifting the same computational work (12.2 kWh) from high-carbon overnight hours to solar-powered daytime windows, we reduced emissions from 3.03 kgCO2 to 1.81 kgCO2. This saved 1.22 kgCO2 across the 21 experiments.</p>
</li>
<li>
<p><strong>Three-tier distribution prevents stampede</strong>: By using multiple thresholds (225/175/125 gCO2/kWh), we distributed load across the solar valley rather than clustering everything at the absolute minimum. All 21 jobs completed successfully without hitting max-delay timeouts.</p>
</li>
<li>
<p><strong>The trade-off is real but manageable</strong>: Carbon-aware scheduling stretched wall-clock time from 16 hours to 51 hours (3.2× longer). But for batch workloads like hyperparameter sweeps, this is often acceptable; we don't <em>need</em> results in 16 hours if we can get them in 2 days, having emitted 40% less carbon along the way.</p>
</li>
<li>
<p><strong>Priority queue based on carbon intensity signal works</strong>: Not all experiments are equal. Fast feedback on baseline adjacent (Tier 1) configurations, a bit more waiting for long shots (Tier 3). Tier 1 results were available within the first day, maintaining research velocity.</p>
</li>
<li>
<p><strong>The best model came from a Tier 3 experiment</strong>: Our top performer (r=32, alpha=128, lr=1e-4, dropout=0.05) was a "long shot" that waited for optimal carbon conditions (123 gCO2/kWh). It achieved 12% better validation loss than our baseline.</p>
</li>
</ul>
<h3>What's Next</h3>
<p>Future work, and a potential part 3 in this series, might explore intelligent scheduling with carbon intensity forecasts as well as scaling up to cloud GPU providers where carbon data varies by region.</p>
<h3>Interested in implementing something similar in your organization?</h3>
<p>If automated carbon awareness for your ML infrastructure sounds appealing, we're available to help. Whether you're looking to deploy Compute Gardener, customize it for your use case or explore new or advanced carbon optimization strategies, don't hesitate to <a href="https://www.compute-gardener.com/contact">reach out</a>. Let's work together to advance sustainable computing practices.</p>
<hr>
<p><em><a href="https://github.com/elevated-systems/compute-gardener-scheduler">Compute Gardener</a> is an open-source Kubernetes scheduler that enables carbon-aware workload scheduling across hybrid clouds. Join us in making carbon-aware computing the default, not the exception.</em></p>]]></content:encoded>
            <enclosure url="https://www.compute-gardener.com/blog/images/legoVerticalGarden.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[Making ML Training Carbon-Aware with Compute Gardener (Part 1)]]></title>
            <link>https://www.compute-gardener.com/resources/blog/ml-training-carbon-aware-pt1</link>
            <guid isPermaLink="false">https://www.compute-gardener.com/resources/blog/ml-training-carbon-aware-pt1</guid>
            <pubDate>Fri, 03 Oct 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[Part 1 showcases how Compute Gardener can lessen carbon emissions of ML training, without any code changes.]]></description>
            <content:encoded><![CDATA[<p><em>How we reduced deferrable training jobs' carbon emissions by ~30% without changing a single line of code</em> 📉🌿</p>
<h3>The Problem: ML's Hidden Carbon Cost</h3>
<p>Every day and all across the world, thousands of machine learning (ML) engineers and data scientists hit "submit" on their training or fine-tuning jobs. Whether "locally" or in a data center somewhere, graphics processing units (GPUs) spin up immediately, regardless of how clean the energy mix on the grid is at that place and time. Without intervention, execution time is dictated more so by the eccentricities and daily working patterns of teams than an optimal, carbon-aware strategy.</p>
<p>In this post, we'll document a recent experiment to limit model training carbon emissions, one that didn't require any human intervention after initial setup. For our purposes, a training job will involve training the ResNet50 model on the CIFAR-100 dataset for 30 epochs.</p>
<p>Truthfully, this isn't the most cutting edge nor demanding task in 2025... but it should provide a somewhat representative training workload which is "bite sized" and reproducible for demonstrating carbon-aware scheduling principles broadly.</p>
<p>A few details:</p>
<ul>
<li>A single ResNet50 training run 🤖 on one of our consumer grade cards (RTX 3090) consumes ~0.475 kWh of energy (~57 minutes at ~500W total system power). 🔥⚡
<ul>
<li>That's enough energy to charge my partner's Electric SUV 🔋🛞 with about 1.5 miles of range.</li>
</ul>
</li>
<li>At higher grid intensity times (usually overnight in CalISO region) we can expect to see 300 or more gCO2eq/kWh vs 100 or fewer gCO2eq/kWh at lower intensity times (usually early afternoon). That crazy unit is "grams of carbon dioxide equivalent per kilowatt-hour".
<ul>
<li>That can mean hundreds of grams of CO2 difference per run, solely due to execution time. I find it hard to make sense of this value, until I remember that I measure out only 15g of coffee beans to grind each morning. ☕🫘</li>
</ul>
</li>
</ul>
<p>While this experiment represents one engineer's jobs for a week, imagine it extrapolating out to hundreds of runs per team per month across many organizations... and the true magnitude of the opportunity to optimize training for carbon, with minimal hassle, starts to come into focus. 🔎🌐</p>
<h3>Enter Temporal Shifting</h3>
<p>What if <strong>deferrable</strong> training jobs could wait for cleaner energy? By "deferrable," we mean workloads where no human is waiting for immediate results and no downstream system is blocked on completion (ex: batch retraining, experimental model iterations, scheduled data processing pipelines, research experiments). These are fundamentally different from customer-facing inference services, APIs or real-time applications where milliseconds matter.</p>
<p>Meanwhile, the grid's carbon intensity varies by 2-3x throughout the day in many regions. Time shifting as a strategy is nothing new. It's been discussed and adopted for years, but there wasn't as much tooling to simplify and automate as there ought to have been. In particular, we were interested in a flexible and extensible approach using the Kubernetes scheduler plugin framework.</p>
<p>Key insight: <strong>Deferrable workloads + Time flexibility = Carbon savings</strong>. We're not talking about delaying production API responses, but rather the training jobs that <em>could</em> wait hours or even days for optimal conditions... but only if the friction and overhead of delaying them isn't too high.</p>
<h3>Compute Gardener: A Secondary Scheduler for Kubernetes</h3>
<p>Rather than asking engineers to change their workflows, what if we made the infrastructure itself carbon-aware? That's exactly what our <a href="https://www.compute-gardener.com/solutions/open-source-scheduler">open-source Kubernetes scheduler</a> does.</p>
<h4>What It Is</h4>
<ul>
<li>A carbon-aware Kubernetes scheduler that runs alongside the default scheduler</li>
<li>Evaluates real-time grid carbon intensity before scheduling</li>
<li>Defers non-critical workloads to cleaner time windows</li>
<li>Ensures jobs run within some maximum delay (configurable, defaults to 24hrs)</li>
</ul>
<h4>What It Isn't</h4>
<ul>
<li>A replacement for your existing default scheduler; only workloads that explicitly opt-in are affected</li>
<li>An approach requiring code modification (whether training, inference or batch processing code)</li>
<li>A strategy that asks you to sacrifice reliability for sustainability</li>
</ul>
<h3>Real-World Testing: A Week of ML Training</h3>
<p>To validate this approach, we designed a week-long experiment with semi-realistic training patterns, measuring both the carbon impact and operational effects of carbon-aware scheduling. This occurred 22nd-26th Sept '25.</p>
<h4>The Workload</h4>
<ul>
<li><strong>Model</strong>: ResNet50 (25M parameters)</li>
<li><strong>Dataset</strong>: CIFAR-100 (100 classes, 50K training images)</li>
<li><strong>Hardware</strong>: Single RTX 3090 (24GB VRAM)</li>
<li><strong>Duration</strong>: ~1 hour per run</li>
<li><strong>Pattern</strong>: Each day we simulated a typical ML engineer's daily workflow with 4 job submissions representing common trigger points throughout the workday and overnight automation:
<ul>
<li>Morning iteration: caffeine-fueled submission at 10:19am</li>
<li>Afternoon collab: "last chance" before EOD submission at 5:41pm</li>
<li>Midnight warrior: poor work-life balance induced submission at 11:12pm</li>
<li>Overnight auto-infra: re-training triggered as part of data ingestion pipeline at 3:55am</li>
</ul>
</li>
</ul>
<h4>The Setup</h4>
<p>We know not everyone has ready access to a Kubernetes cluster, but very similar patterns could be applied in other cloud/HPC orchestrated environments or even on local workstations.</p>
<p>For those who <em>are</em> responsible for such cluster(s) (DevOps teams, lead engineers, other tech decision makers), the aim was to ensure our scheduler would be easy to get up and running quickly. After install, it should be ready to start mitigating real-world emissions immediately with minimal-to-no further configuration. Compute Gardener uses the <a href="https://app.electricitymaps.com">Electricity Maps</a> API for real-time carbon intensity data. The free tier works well for this experiment but is limited to accessing live data for only a single grid region.</p>
<pre><code class="hljs language-yaml"><span class="hljs-comment"># standard k8s Job requesting secondary scheduler</span>
<span class="hljs-attr">apiVersion:</span> <span class="hljs-string">batch/v1</span>
<span class="hljs-attr">kind:</span> <span class="hljs-string">Job</span>
<span class="hljs-attr">metadata:</span>
  <span class="hljs-attr">name:</span> <span class="hljs-string">ml-training-experiment</span>
<span class="hljs-attr">spec:</span>
  <span class="hljs-attr">template:</span>
    <span class="hljs-attr">spec:</span>
      <span class="hljs-comment"># The only change needed ↓</span>
      <span class="hljs-attr">schedulerName:</span> <span class="hljs-string">compute-gardener-scheduler</span>
      <span class="hljs-attr">containers:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">pytorch-training</span>
        <span class="hljs-attr">image:</span> <span class="hljs-string">pytorch/pytorch:2.1.0-cuda12.1-cudnn8-runtime</span>
        <span class="hljs-attr">command:</span>
          <span class="hljs-bullet">-</span> <span class="hljs-string">python</span>
          <span class="hljs-bullet">-</span> <span class="hljs-string">/train.py</span>
        <span class="hljs-attr">resources:</span>
          <span class="hljs-attr">requests:</span>
            <span class="hljs-attr">nvidia.com/gpu:</span> <span class="hljs-number">1</span>
</code></pre>
<p><strong>Note</strong>: This example is simplified for clarity. A real job would include volume mounts for your training script and data, possibly a ConfigMap for hyper-parameters and other standard Kubernetes configuration.</p>
<h4>The Configuration</h4>
<p>By default, the Compute Gardener (CG) Scheduler uses a 24hr maximum delay and 200 gCO2eq/kWh intensity threshold. These can both be easily overridden with custom pod annotations. But in the spirit of keeping the experiment simple and reproducible, we stuck with the defaults.</p>
<p><strong>What happens when jobs queue up?</strong> If grid intensity stays high long enough, CG enforces a maximum delay (default 24hrs), so jobs will run even at higher intensity rather than miss their deadline. Think of it as a carbon budget with a safety valve, not a hard gate that could block critical work.</p>
<h3>The Results</h3>
<p>The results are promising, ~30% reduction in emissions... but they are also quite dependent on grid intensity and workload schedules. In CalISO, last week, with this pattern of jobs, we'd argue, the opportunity was large enough to warrant pursuing.</p>
<p><strong>Note on geographic variation</strong>: These savings reflect CalISO's grid characteristics. While many grids now exhibit daily carbon intensity variation, the magnitude differs by region. Check <a href="https://app.electricitymaps.com">Electricity Maps</a> to assess your grid's potential. You'll likely see some real savings if your grid region has daily intensity swings of >100 gCO2eq/kWh and a threshold is chosen based on local grid region history.</p>
<h4>Week Overview</h4>
<ul>
<li><strong>Work Week</strong> 22nd-26th of September 2025</li>
<li><strong>Total Jobs</strong>: 20 (4 each day) training runs simulating a few data science workflows</li>
<li><strong>Without CG</strong>: All would have run immediately at submission time</li>
<li><strong>With CG</strong>: Strategic delays based on real-time grid carbon intensity</li>
</ul>
<h4>Carbon Impact</h4>
<table>
<thead>
<tr>
<th>Metric</th>
<th>Without CG</th>
<th>With CG</th>
<th>Reduction</th>
</tr>
</thead>
<tbody>
<tr>
<td>Avg Carbon Intensity</td>
<td>231 gCO2eq/kWh</td>
<td>165 gCO2eq/kWh</td>
<td>29%</td>
</tr>
<tr>
<td>Total Emissions</td>
<td>2.26 kgCO2eq</td>
<td>1.63 kgCO2eq</td>
<td>28%</td>
</tr>
<tr>
<td>Jobs Reducing Carbon</td>
<td>0%</td>
<td>55%</td>
<td>-</td>
</tr>
<tr>
<td>Avg Delay</td>
<td>0 hours</td>
<td>3.63 hours</td>
<td>-</td>
</tr>
</tbody>
</table>
<p>Since only 55% of the jobs encountered were delayed, those were the only ones reducing emissions. This value and the average delay duration per job are greatly influenced by how aggressively the intensity threshold and max delay are set.</p>
<p>Remember, all of this can scale up from workstations to data centers and beyond. The real goal is to show that compute can operate flexibly, in ways aligned to the grid and related signals.</p>
<h4>Quick View</h4>
<p><img src="/blog/images/shiftedJobs.png" alt="Chart showing intensity influenced time shifting"></p>
<p><strong>Figure 1</strong>: Grid carbon intensity (top), ComputeGardener shifted jobs (middle) and unshifted jobs (bottom) over nearly a day. Blue represents the midnight job, green the automated job, orange the morning job and yellow the end of day job.</p>
<h4>Key Findings</h4>
<p>Just considering this one week's worth of data, in CalISO region, we can say:</p>
<ol>
<li><strong>Peak intensity hours</strong> (3-6 AM): Carbon intensity averaged ~350 gCO2eq/kWh</li>
<li><strong>Optimal windows</strong> (12-4 PM): Carbon intensity averaged ~120 gCO2eq/kWh</li>
<li><strong>Automation jobs</strong>: The best savings usually came from the overnight jobs, most often being delayed around 6 or 7 hrs, until the morning. For example, the greatest carbon savings for a job was 90.1 gCO2eq. It executed at 158 gCO2eq/kWh, 8.9 hours after it first appeared when the intensity was 351 gCO2eq/kWh.</li>
<li><strong>No failed jobs</strong>: 100% completion rate despite delays and no jobs hit their max delay</li>
</ol>
<p>There's still a lot of low hanging fruit to pick here. Whereas this experiment, and Compute Gardener by default, uses a simple carbon intensity threshold, we'll soon be launching more sophisticated intensity forecast based logic. Essentially, rather than simply letting jobs execute as soon as intensity falls below a threshold, actually try to find the lowest intensity times, in the near future, to delay until.</p>
<h4>Reproducibility</h4>
<p>All experiment data, code and training scripts are available in our <a href="https://github.com/elevated-systems/compute-gardener-scheduler/tree/8a33a3e3d00d6a90152ee671a664fbccce5c5f56/docs/carbon-aware-ml-experiments/resnet-pt1/">GitHub repo</a>. We encourage you to reproduce these results in your own environment and share your findings.</p>
<h3>Adoption: A couple minutes to Carbon Action</h3>
<h4>Step 1: Install Compute Gardener (One-time, 3 minutes)</h4>
<pre><code class="hljs language-bash"><span class="hljs-comment"># Add the Helm repository</span>
helm repo add compute-gardener https://elevated-systems.github.io/compute-gardener-scheduler
helm repo update

<span class="hljs-comment"># Standard installation - Requires Electricity Maps API key but works with FREE tier</span>
helm install compute-gardener-scheduler compute-gardener/compute-gardener-scheduler \
  --namespace compute-gardener \
  --create-namespace \
  --<span class="hljs-built_in">set</span> carbonAware.electricityMap.apiKey=YOUR_API_KEY
</code></pre>
<h4>Step 2: Leverage It (add per pod spec, 1 minute each)</h4>
<pre><code class="hljs language-yaml"><span class="hljs-attr">spec:</span>
  <span class="hljs-attr">schedulerName:</span> <span class="hljs-string">compute-gardener-scheduler</span> <span class="hljs-comment"># That's it!</span>
</code></pre>
<h4>Step 3: [Optional] Fine-tuning</h4>
<ul>
<li>Adjust carbon thresholds based on your grid region and workload urgency</li>
<li>Set maximum delays that match your SLAs and persnickety engineers' expectations</li>
<li>Configure time-of-use pricing awareness, if applicable in your environment</li>
</ul>
<h3>Beyond Simple Training: Production ML Pipelines</h3>
<p><em>This sets the foundation for <a href="https://www.compute-gardener.com/resources/blog/ml-training-carbon-aware-pt2">Part 2</a>, where we'll explore a more complex and real-world training scenario</em></p>
<p>While ResNet training demonstrates the concept, this is just the beginning. In 2025, many organizations and enthusiasts are fine-tuning LLMs for domain-specific tasks and the carbon impact is massive. We're talking multi-GPU clusters running for hours or days... each job.</p>
<p><em>Next post: <strong>LLM LoRA Fine-tuning with Ray + Compute Gardener</strong>—how we made LLM training carbon-aware, handling workloads that represent the cutting edge of today's ML infrastructure. If you're fine-tuning models with (Kube)Ray, you won't want to miss this!</em></p>
<h3>Interested in implementing something similar in your organization?</h3>
<p>If automated carbon awareness for your ML infrastructure sounds appealing, we're available to help. Whether you're looking to deploy Compute Gardener, customize it for your use case or explore advanced carbon optimization strategies, our <a href="https://www.compute-gardener.com/solutions/consulting-services">consulting services</a> team can guide you through the process. Don't hesitate to <a href="https://www.compute-gardener.com/contact">reach out</a> - let's work together to advance sustainable computing practices.</p>
<p>Have questions about implementation? Check our <a href="https://www.compute-gardener.com/resources/faq">FAQ page</a> for answers to common questions about installation, configuration, and best practices.</p>
<hr>
<p><em><a href="https://github.com/elevated-systems/compute-gardener-scheduler">Compute Gardener</a> is an open-source Kubernetes scheduler that enables carbon-aware workload scheduling across hybrid clouds. Join us in making carbon-aware computing the default, not the exception.</em></p>]]></content:encoded>
            <enclosure url="https://www.compute-gardener.com/blog/images/legoGardenUnderground.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[The Carbon-Aware Computing Ecosystem: Progress, Patterns and our Race Against Time]]></title>
            <link>https://www.compute-gardener.com/resources/blog/ecosystem-patterns</link>
            <guid isPermaLink="false">https://www.compute-gardener.com/resources/blog/ecosystem-patterns</guid>
            <pubDate>Mon, 30 Jun 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[Lots to celebrate and lots yet to do!]]></description>
            <content:encoded><![CDATA[<p>The carbon-aware computing ecosystem is having a "moment". About a week ago, Electricity Maps <a href="https://www.linkedin.com/posts/psegonne_electricity-maps-carbon-aware-scheduler-activity-7340676457360252930-gdOP">announced</a> that their API now natively handles cloud-to-grid region mapping; a feature that means developers can query carbon intensity by AWS region or GCP zone without maintaining their own translation tables. Further, last month, I had an inspiring conversation with Ryan Singman covering lots of ground, including one of the more elegant and recent tools in the <a href="https://docs.carbonaware.dev/">CarbonAware</a> toolbox. In particular, a Prefect framework Python decorator approach that makes carbon-aware orchestration as simple as prefixing <code>@carbon_aware</code> to a function. And here at Compute Gardener, we're seeing increased adoption of our Kubernetes scheduler that enables carbon-aware workload scheduling without touching a single line of application code.</p>
<p>This should be cause for celebration. The ecosystem is maturing. Tools are becoming more sophisticated. Adoption barriers are falling.</p>
<p>And yet... latest projections show data center energy consumption (at least) doubling between now and 2030. GenAI workloads alone are expected to consume as much electricity as entire countries. We're in a race where the finish line keeps moving further away, faster than we're running.</p>
<p>This is the dual reality of carbon-aware computing in 2025: We're making real progress, but it's not enough. We're building better tools, but adoption isn't keeping pace with growth. We have solutions that work today. They are proven, tested and ready to deploy but they remain underutilized while energy demands soar.</p>
<p>Fortunately, the patterns emerging in our community show us a path forward. Not through any single tool or approach, but through an ecosystem where each solution serves its users best while amplifying the impact of others. Where a Python developer can add carbon awareness with a decorator, a DevOps engineer can enable it cluster-wide with a scheduler configuration and a cloud architect can optimize placement decisions through intelligent APIs.</p>
<p>Let me show you what this looks like in practice, why it matters more than ever and how you can start reducing your compute responsible carbon footprint today. Not someday, but today, with tools that already exist and patterns that already work.</p>
<p>While the challenge is growing faster than our solutions are currently being adopted, every kilowatt-hour shifted to a cleaner time, every workload deferred during peak carbon intensity, every optimization deployed—they all count. And they count faster when we work together.</p>
<h3>Emerging Community Patterns</h3>
<p>The carbon-aware computing space is crystallizing around three complementary patterns, each serving somewhat different users and use cases. Understanding these patterns (and how they work together) is key to accelerating adoption.</p>
<h4>Developer-First Approaches: Code-Level Integration</h4>
<p>Ryan Singman and the team at CarbonAware have pioneered what might be the most elegant entry point for developers: <a href="https://docs.carbonaware.dev/integrations/prefect/">a decorator that makes any Python function running in Prefect/Airflow carbon-aware</a>. Their approach is beautifully simple:</p>
<pre><code class="hljs language-python"><span class="hljs-meta">@carbon_aware(<span class="hljs-params">max_intensity=<span class="hljs-number">100</span></span>) </span><span class="hljs-comment"># Everything but this line remains unchanged</span>
<span class="hljs-keyword">def</span> <span class="hljs-title function_">train_model</span>():
    model.fit(x_train, y_train)
</code></pre>
<p>This pattern shines because it meets developers where they are. No infrastructure changes. No DevOps coordination. Just add a decorator and your function automatically runs during lower intensity periods.</p>
<p>The limitation? It requires (minor) code changes. Legacy applications, vendor software or containerized workloads can't easily benefit without modification... which is not always practical or supported by others in an org. But for greenfield development and Python-heavy workflows, it's an immediate win!</p>
<h4>Infrastructure-Level Solutions: Intelligent APIs</h4>
<p><a href="https://www.linkedin.com/posts/psegonne_electricity-maps-carbon-aware-scheduler-activity-7340676457360252930-gdOP">Electricity Maps' recent announcement</a> represents another crucial pattern: moving complexity to specialized services. Their API now accepts queries like "What's the carbon intensity for AWS us-east-1?" and handles all the messy details of mapping cloud regions to electrical grids.</p>
<p>This is more than a convenience, it's a fundamental shift in how we think about carbon-aware infrastructure. Instead of every tool maintaining its own mapping tables (guilty as charged; we have one in Compute Gardener codebase), we can now rely on a constantly maintained and  authoritative source.</p>
<p>Another of the CarbonAware projects, <a href="https://github.com/carbon-aware/cloudinfo/">cloudinfo project</a>, has been instrumental in pushing this direction, creating open mappings between cloud providers and grid regions. The fact that Electricity Maps integrated similar functionality shows how community ingenuity and collaboration drive real improvements.</p>
<h4>Orchestration-Layer Tools: Zero Code Change Impact</h4>
<p>This brings us to the pattern we've focused on at Compute Gardener: orchestration-level carbon awareness. By implementing carbon-aware scheduling at the Kubernetes layer, we can affect existing workloads without any code modifications.</p>
<p>Kubernetes already has a pluggable scheduler architecture. By deploying Compute Gardener as a secondary scheduler, teams can opt workloads into carbon-aware scheduling with a simple "annotation":</p>
<pre><code class="hljs language-yaml"><span class="hljs-attr">apiVersion:</span> <span class="hljs-string">batch/v1</span>
<span class="hljs-attr">kind:</span> <span class="hljs-string">Job</span>
<span class="hljs-attr">metadata:</span>
  <span class="hljs-attr">name:</span> <span class="hljs-string">my-analysis-job</span>
<span class="hljs-attr">spec:</span>
  <span class="hljs-attr">template:</span>
    <span class="hljs-attr">spec:</span>
      <span class="hljs-comment"># This is all a job needs to specify in order to delegate to a carbon aware scheduler</span>
      <span class="hljs-comment"># (with default settings; custom thresholds, max delays, etc. can be further annotated as needed)</span>
      <span class="hljs-attr">schedulerName:</span> <span class="hljs-string">compute-gardener-scheduler</span>
      <span class="hljs-attr">containers:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">my-analysis-job</span>
        <span class="hljs-attr">image:</span> <span class="hljs-string">existing-build-train-etl-etc:latest</span>  <span class="hljs-comment"># No changes to containers or related config needed!</span>
</code></pre>
<p>No application changes. No risk to existing workloads. Just carbon-aware scheduling for any containerized workload that could leverage it.</p>
<h3>The Collaborator's Dividend</h3>
<p>Here's where it gets interesting (though not unexpectedly so, for those who believe in the value of open source software and data). These patterns aren't competing, they work in concert. And that composition is accelerating progress for everyone.</p>
<p>Take our recent decision to remove region mapping code from Compute Gardener. We spent some real engineering time towards building and maintaining cloud-to-grid mappings. But with Electricity Maps' new API endpoints and Ryan's open cloudinfo data, we're about to delete that code entirely.</p>
<p>Software engineers know that removing lines of code can OFTEN feel even better than adding new, especially when it allows for doing more with less. Less maintenance work for us, better data for our users and more time to focus on what we do best: making Kubernetes scheduling smarter.</p>
<p>This is the collaborator's dividend in action. When CarbonAware focuses on developer experience, Electricity Maps on data accuracy and accessiblity and Compute Gardener on orchestration, the whole ecosystem gets stronger. Users can choose tools that fit their constraints while benefiting from shared infrastructure.</p>
<h3>Why This Matters Now: The Urgency Gap</h3>
<p>Let's talk about the gassy elephant in the room: we're not moving fast enough.</p>
<p>Data center electricity consumption is projected to double by 2030, reaching 1,000 TWh annually; roughly the entire electricity consumption of Japan. GenAI workloads are accelerating this trend, with training runs consuming megawatt-hours and inference at scale beginning to dwarf traditional computing workloads.</p>
<p>Meanwhile, our carbon budgets are shrinking. To stay under 1.5°C of warming, we need to cut emissions by 45% by 2030. That's five years out. Not five years to commission a panel, five years to achieve.</p>
<p>This is why every deferred workload matters. When Compute Gardener delays a batch job from running at 500 gCO2eq/kWh to 100 gCO2eq/kWh, that's an 80% reduction in carbon emissions for that workload. Multiply that by thousands of jobs across hundreds of clusters and the impact becomes substantial.</p>
<p>But it's still not enough. Not when adoption remains limited to the sustainability-conscious few. Not when most organizations still view carbon awareness as a "nice to have" rather than a business imperative.</p>
<h3>Practical Integration Patterns</h3>
<p>So how do we accelerate? By making adoption so easy that NOT using carbon-aware computing becomes the exception. Here are patterns we're seeing work:</p>
<h4>A Layered Approach</h4>
<p>Start with orchestration-level tools for immediate impact to existing infra and layer in developer tools for new applications:</p>
<ol>
<li><strong>Week 1</strong>: Deploy Compute Gardener for all deferrable workloads</li>
<li><strong>Month 1</strong>: Add carbon-aware decorators to data pipeline code</li>
<li><strong>Quarter 1</strong>: Integrate Electricity Maps API for multi-region deployment decisions</li>
</ol>
<h4>Quick Wins</h4>
<p>Focus on the easiest, highest-impact workloads first:</p>
<ul>
<li><strong>Batch jobs</strong>: Usually perfect for time-shifting</li>
<li><strong>CI/CD pipelines</strong>: Run builds and tests during cleaner hours</li>
<li><strong>Data processing</strong>: ETL and analysis jobs are often ideal for carbon-aware scheduling</li>
<li><strong>Model training</strong>: Ridiculously high energy use makes carbon awareness critical</li>
</ul>
<h4>The Enterprise Pattern</h4>
<p>For larger organizations, create a carbon-aware platform layer:</p>
<ol>
<li>Deploy orchestration tools cluster-wide</li>
<li>Provide and encourage developer libraries and decorators</li>
<li>Integrate carbon metrics into existing dashboards</li>
<li>Set carbon budgets alongside compute budgets</li>
</ol>
<h3>Building the Future We Need</h3>
<p>The patterns are clear. The tools exist. The urgency is undeniable. What we need now is adoption at scale.</p>
<p>This is where you come in. Whether you're a developer who can add a decorator to your next function, a DevOps engineer who can enable carbon-aware scheduling or a leader who can mandate carbon metrics alongside performance metrics... YOU have a role to play.</p>
<p>Start where you are:</p>
<ul>
<li><strong>Have a Kubernetes cluster?</strong> Deploy <a href="https://github.com/elevated-systems/compute-gardener-scheduler">Compute Gardener</a> today</li>
<li><strong>Writing Prefect/Airflow pipeline code?</strong> Try <a href="https://docs.carbonaware.dev/integrations/prefect/">CarbonAware's decorator</a> for your next function</li>
<li><strong>Architechting multi-region deployments?</strong> <a href="https://www.linkedin.com/posts/psegonne_electricity-maps-carbon-aware-scheduler-activity-7340676457360252930-gdOP">Use Electricity Maps' API</a> for placement decisions</li>
<li><strong>Building something new?</strong> Design carbon consideration in from the start</li>
</ul>
<p>Share what you learn. The community grows stronger with every blog post, every GitHub issue and every conference talk about real-world carbon-aware computing.</p>
<p>And if you need help along the way (whether it's implementing these patterns, measuring impact or building a carbon-aware strategy), please reach out! We're all in this together and the clock is ticking.</p>
<p>The carbon-aware computing ecosystem is more than mature enough to make a difference. The patterns work. The tools exist. The only question is: will we deploy them fast enough?</p>
<p>Every kilowatt-hour shifted to cleaner times matters. Every optimized workload counts. We know the time to act is now.</p>
<hr>
<p><em><a href="https://github.com/elevated-systems/compute-gardener-scheduler">Compute Gardener</a> is an open-source Kubernetes scheduler that enables carbon-aware workload scheduling across hybrid clouds. Join us in making carbon-aware computing the default, not the exception.</em></p>]]></content:encoded>
            <enclosure url="https://www.compute-gardener.com/blog/images/roseyDatacenter.jpg" length="0" type="image/jpg"/>
        </item>
        <item>
            <title><![CDATA[Average or Marginal? Navigating Intensity Signals in Carbon-Aware Computing]]></title>
            <link>https://www.compute-gardener.com/resources/blog/carbon-intensity-signal-debate</link>
            <guid isPermaLink="false">https://www.compute-gardener.com/resources/blog/carbon-intensity-signal-debate</guid>
            <pubDate>Wed, 14 May 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[How should we consider these signals when it comes to scheduling?]]></description>
            <content:encoded><![CDATA[<p>As the <a href="https://github.com/elevated-systems/compute-gardener-scheduler">Compute Gardener Scheduler</a> continues to evolve, I've been fortunate enough to engage in some fascinating conversations around a fundamental question in carbon-aware computing: should we optimize for average or marginal carbon intensity when scheduling workloads? The question may seem nuanced and technical, but it could have meaningful implications for how we build truly effective carbon-aware systems.</p>
<h3>The Signal Question</h3>
<p>If, like me, you're new to the concepts:</p>
<p><strong>Average carbon intensity</strong> tells us the emissions associated with the overall electricity mix on the grid at a given moment — essentially, what's the carbon footprint of a kWH (kilowatt-hour) of electricity right now, considering all generation sources currently active.</p>
<p><strong>Marginal carbon intensity</strong> attempts to predict which generation sources would respond to a new load being added to the grid — in other words, what's the carbon footprint of the <em>next</em> kWh if we were to consume it right now.</p>
<p>The difference initially seems subtle, but it can be substantial. In many grids, the marginal generator (the one that ramps up to meet new demand) might be a natural gas plant, even when solar and wind make up a significant portion of the current mix.</p>
<h3>The Community Conversation</h3>
<p>This topic has sparked lively debates in the climate tech community. I first became aware of it through a conversation including Tammy Sukprasert, a researcher at UMass Amherst, on the <a href="https://podcasts.castplus.fm/e/v855j7m8-finding-signal-amongst-the-noise-in-carbon-aware-software">Environment Variables podcast</a>. In that episode, she highlighted the theoretical differences between average and marginal emissions signals and mentioned that organizations like WattTime have been exploring the use of marginal signals. She was kind enough, a few weeks after the episode, to talk with me and help me begin to grok the distinction.</p>
<p>During the recent San Francisco Climate Week, I had the opportunity to briefly discuss this with Olivier Corradi, CEO of Electricity Maps API, and a few of his colleagues. Their perspective is that average signals are more reliable, accessible and ultimately more actionable for most use cases.</p>
<p>WattTime has been a prominent voice in the space examining the potential benefits of marginal emissions. Their argument is that marginal emissions might more accurately reflect the true impact of new electrical loads on the grid. For what it's worth, I haven't had the chance to talk nearly as much with their team or others who follow this school of thought.</p>
<h3>The Case for Marginal Signals</h3>
<p>WattTime <a href="https://watttime.org/data-science/data-signals/average-vs-marginal/">presents a compelling economic and operational case</a> for marginal intensity signals. They argue that while average emissions tell us about the overall grid composition, they don't necessarily reflect what happens when we decide to consume electricity at a specific moment. Grid operators dispatch generation sources in order of cost (known as merit order dispatch), which means the generators responding to new demand often differ from the average mix. From an economic perspective, this is analogous to the difference between average cost and marginal cost - what matters for decision-making is the impact of your next action, less so the previous state of the system.</p>
<p>For carbon-aware computing specifically, this distinction becomes meaningful because our goal isn't just to measure or attribute emissions, but to actively reduce them through timing decisions. If a data center chooses to run a batch workload now versus in three hours, the real-world emissions impact of that decision is determined by which generators respond to that load - the marginal sources - not the average grid mix. Studies by researchers at Rocky Mountain Institute (<a href="https://rmi.org/wp-content/uploads/2017/05/RMI_Document_Repository_Public-Reprts_RMI-TheEconomicsofDemandFlexibilityExecSummary.pdf">Dyson &#x26; Mandel et al., 2017</a>) and the University of Michigan (<a href="https://pubs.acs.org/doi/10.1021/acs.est.7b00034">Li et al., 2017</a>) have validated that timing decisions based on marginal emissions can lead to greater carbon reductions than those based on average emissions, particularly in grids with diverse generation sources.</p>
<h3>The Complexity of Marginal Signals</h3>
<p>The theory behind marginal signals is compelling. However, several practical challenges have informed our current approach with Compute Gardener:</p>
<ol>
<li>
<p><strong>Hyperlocal Dependencies</strong>: Marginal signals can vary significantly based on precise grid connection points. Without extremely granular location data (beyond what most cloud providers expose), the signal's accuracy degrades.</p>
</li>
<li>
<p><strong>Load Scale Assumptions</strong>: Many marginal intensity models assume relatively large loads that can actually influence dispatch decisions. For individual computing workloads, even substantial clusters, this assumption may not hold.</p>
</li>
<li>
<p><strong>Coordination Challenges</strong>: While marginal signals aim to reduce emissions by capturing the impact of new loads, research has identified scenarios where they could backfire. Research on load synchronization issues has shown that when many distributed actors independently respond to the same marginal emissions signal without coordination, they can create new demand peaks that could potentially trigger high-carbon peaker plants (<a href="https://arxiv.org/abs/2106.11750">Radovanovic et al., 2021</a>).</p>
</li>
<li>
<p><strong>Data Availability and Reliability</strong>: Average intensity data is more widely available, standardized and accessible across different regions, making it easier to implement globally consistent policies. Further, it is likely better understood and considered more reliable for the purposes of analytical emissions mitigation validation.</p>
</li>
</ol>
<p>Olivier Corradi of Electricity Maps API has emphasized the coordination challenge in conversations and in their blog series <a href="https://ww2.electricitymaps.com/blog/marginal-emissions-what-they-are-and-when-to-use-them">"Marginal signals explained"</a>, noting that the theoretical benefits of marginal signals can be undermined when applied at scale without proper grid coordination. This synchronization effect is particularly concerning in grids with high renewable penetration that already face steep evening ramps when solar generation decreases, such as California's famous <a href="https://en.wikipedia.org/wiki/Duck_curve">"duck curve"</a> scenario, where rapid ramping requirements in the evening can necessitate firing up more carbon-intensive peaker plants.</p>
<h3>Our Implementation Choice</h3>
<p>For <a href="https://www.compute-gardener.com/solutions/open-source-scheduler">Compute Gardener's initial release</a>, we've chosen to focus on average carbon intensity signals, specifically through the Electricity Maps API. This decision wasn't made lightly and attempts to strike a pragmatic balance between building useful tools now and engaging with the debate as it rages on and we accumulate more data.</p>
<p>Our focus has been on validating the core hypothesis: we can meaningfully reduce emissions by temporally shifting computing workloads based on carbon intensity signals. Starting with average intensity allows us to:</p>
<ol>
<li>
<p><strong>Implement widely</strong>: The scheduler can work across diverse geographic regions with consistent signal quality.</p>
</li>
<li>
<p><strong>Validate quickly</strong>: We can measure and demonstrate emissions reductions in real-world scenarios.</p>
</li>
<li>
<p><strong>Iterate responsibly</strong>: As our understanding evolves, we can incorporate more sophisticated signals without disrupting existing installations.</p>
</li>
<li>
<p><strong>Avoid overcomplicated abstractions</strong>: By starting with a clearer signal, we build interfaces and patterns that make sense to users and avoid premature optimization.</p>
</li>
</ol>
<h3>Looking Forward</h3>
<p>While we've started with average intensity signals, Compute Gardener's architecture is designed to accommodate future signal sources. The modular implementation of our carbon-aware scheduling allows for:</p>
<ol>
<li>
<p><strong>Multiple signal sources</strong>: Organizations with access to high-quality, locationally relevant marginal signals could plug them into the scheduler.</p>
</li>
<li>
<p><strong>Hybrid approaches</strong>: Combining average and marginal signals based on workload characteristics and regional grid dynamics.</p>
</li>
<li>
<p><strong>Spatial shifting</strong>: As we expand beyond temporal optimization to consider moving workloads between regions, we can incorporate both signal types for more sophisticated decision-making.</p>
</li>
</ol>
<h3>The Bigger Context</h3>
<p>This discussion exists within a broader question of how distributed systems should respond to grid carbon signals. Should every individual system independently optimize for carbon, or should there be coordination? Do we need carbon-aware load balancing at the grid level? How might pricing mechanisms better align individual incentives with grid-level outcomes?</p>
<p>These are the questions that keep us climate-focused nerds up at night and they don't have simple or one-size-fits-all answers.</p>
<h3>Your Thoughts?</h3>
<p>I'm curious what you think about this debate. Have you implemented carbon-aware systems using intensity signals? What has your experience been? For those with particular expertise in data center and grid operations, what critical perspectives might I be missing?</p>
<p>This is an exciting and ever evolving conversation and one that will shape how computing adapts to our always constrained world. I look forward to continuing it with you.</p>
<h3>Want to take action now?</h3>
<p>Check out our <a href="https://github.com/elevated-systems/compute-gardener-scheduler">Kubernetes scheduler</a> if you're interested in learning more or are looking for a way to take some real steps forward in your sustainable compute game today!</p>]]></content:encoded>
            <enclosure url="https://www.compute-gardener.com/blog/images/legoFlowerInspection.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[Building a Carbon and Price-Aware Kubernetes Scheduler]]></title>
            <link>https://www.compute-gardener.com/resources/blog/compute-gardener-tech-dive</link>
            <guid isPermaLink="false">https://www.compute-gardener.com/resources/blog/compute-gardener-tech-dive</guid>
            <pubDate>Thu, 20 Mar 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[Compute Gardener Technical Deep Dive]]></description>
            <content:encoded><![CDATA[<p>Kubernetes and cloud infrastructure have revolutionized how we deploy and manage applications and services, but with traditional data center and cloud computing infrastructure now likely responsible for about 4% of global electricity consumption and set to triple to potentially 12% of U.S. electricity in the next three years<a id="ref1" href="#cite1">[1]</a>, now is the time to build energy and emissions awareness into our orchestration systems. In this post, I'll walk through the technical implementation of the Compute Gardener Scheduler, a carbon and price-aware Kubernetes scheduler plugin we've developed; building upon recent advancements in energy-aware computing.<a id="ref2" href="#cite2">[2]</a></p>
<h3>The Challenge</h3>
<p>Standard Kubernetes scheduling doesn't consider energy implications - pods are placed to optimize for resource utilization, spread, affinity and other traditional metrics. But what if we want to:</p>
<ol>
<li>Delay non-urgent workloads until carbon intensity of the grid is lower<a id="ref3" href="#cite3">[3]</a></li>
<li>Run batch jobs during off-peak electricity pricing hours</li>
<li>Track energy consumption for workloads and enforce budgets</li>
<li>Optimize for energy-efficient hardware when available<a id="ref4" href="#cite4">[4]</a></li>
</ol>
<h3>Overview</h3>
<p>We built our solution using Kubernetes' scheduler framework, which allows custom plugins to influence scheduling decisions.<a id="ref7" href="#cite7">[7]</a> The core components include:</p>
<pre><code class="hljs language-bash"><span class="hljs-comment"># Main components of the scheduler</span>
api/      <span class="hljs-comment"># Various data providers' API clients </span>
carbon/   <span class="hljs-comment"># Carbon-aware scheduling implementations (currently Electricity Map API)</span>
config/   <span class="hljs-comment"># Configuration types and validation</span>
metrics/  <span class="hljs-comment"># Prometheus metrics and hardware profiling</span>
price/    <span class="hljs-comment"># Price-aware scheduling implementations (currently time-of-use)</span>
</code></pre>
<p>Our scheduler implements two key extension points in the framework:</p>
<ol>
<li><strong>PreFilter</strong>: Initial validation of scheduling constraints and annotations related to carbon intensity and price</li>
<li><strong>Filter</strong>: Main decision logic that evaluates efficiency and suitability of potential nodes to bind</li>
</ol>
<h3>Decision Flow</h3>
<h4>PreFilter Stage</h4>
<p>The <code>PreFilter</code> stage/method handles initial validation of scheduling constraints and annotations related to carbon intensity and pricing.</p>
<pre><code class="hljs language-go"><span class="hljs-comment">// PreFilter implements the PreFilter interface (simplified)</span>
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(cs *ComputeGardenerScheduler)</span></span> PreFilter(ctx context.Context, state *framework.CycleState, 
                                              pod *v1.Pod) *framework.Status {
    <span class="hljs-comment">// Check pricing constraints, if enabled</span>
    <span class="hljs-keyword">if</span> cs.config.Pricing.Enabled &#x26;&#x26; cs.pricingImpl != <span class="hljs-literal">nil</span> {
        <span class="hljs-keyword">if</span> status := cs.pricingImpl.CheckPriceConstraints(pod, cs.clock.Now()); !status.IsSuccess() {
            <span class="hljs-keyword">return</span> status
        }
    }

    <span class="hljs-comment">// Check carbon intensity constraints, if enabled</span>
    <span class="hljs-keyword">if</span> cs.config.Carbon.Enabled &#x26;&#x26; cs.carbonImpl != <span class="hljs-literal">nil</span> {
        <span class="hljs-comment">// Get threshold from configured threshold</span>
        threshold := cs.config.Carbon.IntensityThreshold
        <span class="hljs-comment">// Override with annotated value, if present</span>
        ...

        <span class="hljs-comment">// Get current carbon intensity</span>
        intensity, err := cs.carbonImpl.GetCurrentIntensity(ctx)
        <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
            <span class="hljs-comment">// If we can't determine carbon intensity, allow pod thru</span>
            <span class="hljs-keyword">return</span> framework.NewStatus(framework.Success, <span class="hljs-string">""</span>)
        }

        <span class="hljs-comment">// Make scheduling decision based on threshold</span>
        <span class="hljs-keyword">if</span> intensity > threshold {
            msg := fmt.Sprintf(<span class="hljs-string">"Current carbon intensity (%.2f) exceeds threshold (%.2f)"</span>, 
                              intensity, threshold)
            <span class="hljs-keyword">return</span> framework.NewStatus(framework.Unschedulable, msg)
        }
    }

    <span class="hljs-comment">// Default to letting pod thru</span>
    <span class="hljs-keyword">return</span> framework.NewStatus(framework.Success, <span class="hljs-string">""</span>)
}
</code></pre>
<h4>Filter Stage</h4>
<p><code>PreFilter</code> occurs without any node awareness. Then, in the <code>Filter</code> stage, we gain node information and can consider our knowledge of node energy use and efficiency in scheduling decisions.</p>
<pre><code class="hljs language-go"><span class="hljs-comment">// Filter implements the Filter interface (simplified)</span>
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(cs *ComputeGardenerScheduler)</span></span> Filter(ctx context.Context, state *framework.CycleState, 
                                          pod *v1.Pod, nodeInfo *framework.NodeInfo) *framework.Status {
    <span class="hljs-comment">// Logic for hardware profiling and node selection</span>
    <span class="hljs-keyword">if</span> cs.config.HardwareProfiling.Enabled &#x26;&#x26; cs.hardwareProfileImpl != <span class="hljs-literal">nil</span> {
        profile := cs.hardwareProfileImpl.GetNodeProfile(nodeInfo.Node().Name)
        <span class="hljs-keyword">if</span> profile == <span class="hljs-literal">nil</span> {
            <span class="hljs-keyword">return</span> framework.NewStatus(framework.Unschedulable, <span class="hljs-string">"No hardware profile available"</span>)
        }

        <span class="hljs-comment">// Apply node selection based on hardware capabilities</span>
        <span class="hljs-keyword">if</span> !cs.nodeSelectionImpl.IsNodeSuitable(profile, pod) {
            <span class="hljs-keyword">return</span> framework.NewStatus(framework.Unschedulable, <span class="hljs-string">"Node not suitable for workload"</span>)
        }
    }

    <span class="hljs-comment">// Default to letting pod thru</span>
    <span class="hljs-keyword">return</span> framework.NewStatus(framework.Success, <span class="hljs-string">""</span>)
}
</code></pre>
<p>This implementation follows the Kubernetes scheduler pattern of returning <code>Unschedulable</code> status when conditions aren't met, which causes the pod to wait in the scheduling queue until conditions change.</p>
<h3>Real-Time Carbon Intensity Data</h3>
<p>The scheduler consumes carbon intensity data from external APIs and makes scheduling decisions based on configurable thresholds. Our solution:</p>
<ol>
<li>Supports pod-level configuration through annotations, allowing different thresholds per workload</li>
<li>Uses caching and failure backoff to tolerate API failures and maintain scheduler reliability</li>
<li>Makes it easy for operators to dynamically override scheduling decisions as preferred</li>
</ol>
<h3>Hardware Profiling and Estimating Node Energy Use</h3>
<p>Accurately modeling power consumption, estimating energy usage, and selecting suitable nodes based on hardware capabilities enables efficient scheduling. It seems like it <em>SHOULD</em> be easy, but most computing hardware wasn't designed with real-time power monitoring as a primary feature.</p>
<p>Fortunately, for Graphical Processing Units (GPUs), we can leverage direct power metrics through NVIDIA's DCGM, which provides reasonably accurate real-time power consumption data to which we can apply a PUE (Power Usage Effectiveness) factor. However, for CPUs and memory, we must rely on a combination of heuristics, frequency scaling information, and utilization patterns to estimate power consumption.</p>
<p>Our approach follows and extends the Green Software Foundation's Software Carbon Intensity (SCI) methodology<a id="ref8" href="#cite8">[8]</a>, adding enhancements for CPU frequency scaling and dynamic power profiling. We believe our estimates are within 5% of actual consumption for calibrated nodes - likely sufficient accuracy for carbon accounting and potential carbon credit validation.</p>
<pre><code class="hljs language-go"><span class="hljs-comment">// calculatePodPower estimates power consumption (simplified)</span>
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">calculatePodPower</span><span class="hljs-params">(nodeName <span class="hljs-type">string</span>, cpu <span class="hljs-type">float64</span>, memory <span class="hljs-type">float64</span>, gpuPower <span class="hljs-type">float64</span>)</span></span> <span class="hljs-type">float64</span> {
    <span class="hljs-comment">// Get hardware profile for the node</span>
    profile := getNodeHardwareProfile(nodeName)
    
    <span class="hljs-comment">// Apply frequency scaling adjustment</span>
    cpuFreq := getCurrentCPUFrequency(nodeName)
    <span class="hljs-keyword">if</span> cpuFreq > <span class="hljs-number">0</span> &#x26;&#x26; profile.BaseFrequency > <span class="hljs-number">0</span> {
        freqRatio := cpuFreq / profile.BaseFrequency
        <span class="hljs-comment">// Power typically scales with square of frequency</span>
        powerRatio := freqRatio * freqRatio
        profile.MaxPower *= powerRatio
    }

    <span class="hljs-comment">// Power-law model for CPU power considering utilization</span>
    cpuPower := profile.IdlePower + 
                (profile.MaxPower - profile.IdlePower) * 
                math.Pow(cpu, <span class="hljs-number">1.4</span>)  <span class="hljs-comment">// Common exponent used in datacenter modeling</span>
                
    <span class="hljs-comment">// Add GPU power with datacenter overhead (PUE)</span>
    totalPower := cpuPower
    <span class="hljs-keyword">if</span> gpuPower > <span class="hljs-number">0</span> {
        totalPower += gpuPower * profile.GPUPUE
    }

    <span class="hljs-keyword">return</span> totalPower
}

<span class="hljs-comment">// Calculate energy using numerical integration</span>
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">CalculateTotalEnergy</span><span class="hljs-params">(records []PodMetricsRecord)</span></span> <span class="hljs-type">float64</span> {
    totalEnergy := <span class="hljs-number">0.0</span>
    
    <span class="hljs-keyword">for</span> i := <span class="hljs-number">1</span>; i &#x3C; <span class="hljs-built_in">len</span>(records); i++ {
        <span class="hljs-comment">// Integrate power over time, summing totalEnergy</span>
        ...
    }

    <span class="hljs-keyword">return</span> totalEnergy
}
</code></pre>
<p>This allows us to model power consumption accurately with dynamic frequencies, and then calculate energy usage over time using numerical integration.</p>
<h3>Performance Considerations</h3>
<p>A key concern with any scheduler is adding latency to scheduling decisions. We implemented several optimizations:</p>
<ol>
<li><strong>Caching</strong>: Both carbon API responses and hardware profiles are cached, ensuring API hiccups never derail a scheduling decision</li>
<li><strong>Parallel Processing</strong>: API requests and metrics collection happen asynchronously wrt core scheduler flow</li>
<li><strong>Bounded Memory</strong>: If capturing metrics, downsampling is used for long-running pods to limit memory usage</li>
<li><strong>Prometheus Integration</strong>: Leverage existing monitoring infrastructure; don't reinvent or duplicate</li>
</ol>
<p>Most importantly, all of this runs as a secondary scheduler, which means:</p>
<ol>
<li>System-critical components continue using the default scheduler; your 24/7 HA services will never even know there's another scheduler in the cluster</li>
<li>Only workloads that opt-in are subject to carbon/price decisions; can opt-in at pod level or namespace level using webhook admission controller</li>
<li>Scheduling delays (capped at a configurable max) cause temporal workload shifting strategies that have shown promising results in reducing carbon emissions<a id="ref5" href="#cite5">[5]</a></li>
</ol>
<h3>Pod Configuration</h3>
<p>Workload creators can opt into carbon/price-aware scheduling by requesting <code>schedulerName: compute-gardener-scheduler</code> in pod spec and then can apply individual job/pod overrides with annotations:</p>
<pre><code class="hljs language-yaml"><span class="hljs-attr">metadata:</span>
  <span class="hljs-attr">annotations:</span>
    <span class="hljs-comment"># Set custom carbon intensity threshold</span>
    <span class="hljs-attr">compute-gardener-scheduler.kubernetes.io/carbon-intensity-threshold:</span> <span class="hljs-string">"200.0"</span>
    <span class="hljs-comment"># Enable price awareness using configMap'd schedules</span>
    <span class="hljs-attr">compute-gardener-scheduler.kubernetes.io/price-enabled:</span> <span class="hljs-string">"true"</span>
    <span class="hljs-comment"># Set energy budget</span>
    <span class="hljs-attr">compute-gardener-scheduler.kubernetes.io/energy-budget-kwh:</span> <span class="hljs-string">"5.0"</span>
    <span class="hljs-comment"># Limit any potential carbon/price delays to a maximum of 12 hrs.</span>
    <span class="hljs-attr">compute-gardener-scheduler.kubernetes.io/max-scheduling-delay:</span> <span class="hljs-string">"12h"</span>
<span class="hljs-attr">spec:</span>
  <span class="hljs-attr">schedulerName:</span> <span class="hljs-string">compute-gardener-scheduler</span>
</code></pre>
<h3>Projected Results and Validation Needs</h3>
<p>Based on our simulations and initial measurements, the scheduler shows promising potential benefits:</p>
<ol>
<li><strong>Carbon reduction</strong>: Testing suggests potential for 50%+ reduction in carbon emissions for time deferrable workloads (mitigations measured 03-17Mar25 with intensity data in CalISO region cycling between common daily lows of 50 and highs of 200+ gCO2eq/kWh)</li>
<li><strong>Cost savings</strong>: Testing indicates 20%+ reduction in electricity costs when leveraging time-of-use (TOU) rates (mitigations measured 03-17Mar25 and considering PGE's E-TOU-B pricing schedule)</li>
<li><strong>Energy tracking</strong>: Previously invisible energy consumption becomes visible and actionable (priceless, right? ;D)</li>
<li><strong>Performance impact</strong>: Testing shows minimal increase in scheduling latency (&#x3C; 100ms per decision; shouldn't be significant considering k8s orchestration timescales)</li>
</ol>
<p>For a medium-large cloud data center with ML training workloads, our simulations project approximately 18 metric tons of CO2 equivalent emissions that could be avoided per month. These estimates align with recent research showing substantial potential for carbon reduction in ML workloads through intelligent scheduling.<a id="ref6" href="#cite6">[6]</a></p>
<p>We're actively seeking partners to help validate these projections in production environments. If you're interested in deploying carbon and/or price-aware scheduling in your Kubernetes clusters, we'd love to collaborate to measure and refine real-world impact. Please reach out via our <a href="https://www.compute-gardener.com/contact">website</a> or <a href="https://github.com/elevated-systems/compute-gardener-scheduler">GitHub</a> repository.</p>
<h3>Future Developments</h3>
<p>As the field of carbon-aware computing continues to evolve, several exciting developments are on the horizon:</p>
<ol>
<li><strong>Integration with Advanced Forecasting</strong>: Leveraging ML, along with weather and various other signals, to predict future carbon intensity and optimize scheduling decisions in real-time.</li>
<li><strong>Enhanced Hardware Profiling</strong>: Developing more accurate models for power consumption across different common cloud hardware configurations, including CPUs, GPUs, and memory.</li>
<li><strong>Global Carbon Markets</strong>: Integrating the scheduler with global carbon markets to enable workloads mitigating carbon emissions, in a calibrated, validated way, to recieve carbon credits.</li>
<li><strong>Cross-Cluster Scheduling</strong>: Extending the scheduler's capabilities to manage carbon emissions across multiple Kubernetes clusters and thereby space.</li>
</ol>
<p>These developments will further enhance the ability of the Compute Gardener to reduce carbon footprints and optimize costs in Kubernetes environments.</p>
<h3>Conclusion</h3>
<p>Building a carbon and price-aware Kubernetes scheduler involves considered integration with Kubernetes core components, external APIs, and hardware-specific optimizations. By creating as a secondary scheduler with an opt-in model, we've made it easy to deploy without disrupting critical workloads while still providing substantial, and immediate, environmental and cost benefits.</p>
<p>Try it out today with your next training or build job!</p>
<p><em>Compute Gardener Scheduler is open source and available on <a href="https://github.com/elevated-systems/compute-gardener-scheduler">GitHub</a>.</em></p>
<h3>Related Reading</h3>
<p>Our work builds on the thoughts and patterns from those in the community who have pioneered research in carbon-aware computing, in particular with a k8s perspective. We're grateful for the foundation they've established, which has made our approach practical and possible. Beyond the sources cited above, <a id="ref9" href="#cite9">[9]</a>, <a id="ref10" href="#cite10">[10]</a>, and <a id="ref11" href="#cite11">[11]</a> have each influenced our designs, as well.</p>
<p><a id="cite1" href="#ref1">[1]</a> Reuters. <a href="https://www.reuters.com/business/energy/ceraweek-data-center-build-out-stokes-fears-overburdening-biggest-us-grid-2025-03-13/">Data center build-out stokes fears of overburdening biggest US grid</a>. March 13, 2025.</p>
<p><a id="cite2" href="#ref2">[2]</a> James, A., &#x26; Schien, D. (2019). <a href="https://ceur-ws.org/Vol-2382/ICT4S2019_paper_28.pdf">A Low Carbon Kubernetes Scheduler</a>. In Proceedings of the 6th International Conference on ICT for Sustainability (ICT4S 2019), Vol. 2382. CEUR Workshop Proceedings.</p>
<p><a id="cite3" href="#ref3">[3]</a> Philipp Wiesner, Ilja Behnke, Dominik Scheinert, Kordian Gontarska, Lauritz Thamsen. <a href="https://arxiv.org/abs/2110.13234">Let's Wait Awhile: How Temporal Workload Shifting Can Reduce Carbon Emissions in the Cloud</a></p>
<p><a id="cite4" href="#ref4">[4]</a> Zhenyu Wen, Renyu Yang, Albert Zomaya. <a href="https://pure.rug.nl/ws/portalfiles/portal/886260758/s11227-023-05506-7.pdf">Energy-Aware Kubernetes Scheduler: Opportunities and Challenges</a></p>
<p><a id="cite5" href="#ref5">[5]</a> Randall Ross, Matt Rutherford, David Grunwald. <a href="https://arxiv.org/abs/2410.15087">Carbon-Aware Computing And Scheduling for CPU-Intensive Workloads in Heterogeneous Clusters</a></p>
<p><a id="cite6" href="#ref6">[6]</a> James Downton, Antonios Katsarakis, Juliana Franco, et al. <a href="https://arxiv.org/abs/2502.09717">Scheduling machine learning training jobs on heterogeneous compute with Carbon signal</a></p>
<p><a id="cite7" href="#ref7">[7]</a> Piontek, T., Haghshenas, K. &#x26; Aiello, M. <a href="https://doi.org/10.1007/s11227-023-05506-7">Carbon emission-aware job scheduling for Kubernetes deployments</a>. J Supercomputer 80, 549–569 (2024).</p>
<p><a id="cite8" href="#ref8">[8]</a> Green Software Foundation. <a href="https://github.com/Green-Software-Foundation/sci/tree/main">Software Carbon Intensity (SCI) Specification</a></p>
<p><a id="cite9" href="#ref9">[9]</a> UMass Solar. <a href="https://github.com/umass-solar/carbon-aware-dag">Carbon-aware-dag</a>. GitHub repository.</p>
<p><a id="cite10" href="#ref10">[10]</a> C3Lab. <a href="https://github.com/c3lab-net/k8s-carbon-aware-scheduler">K8s-carbon-aware-scheduler</a>. GitHub repository.</p>
<p><a id="cite11" href="#ref11">[11]</a> Zemdom. <a href="https://github.com/zemdom/carbon-aware-scheduling">Carbon-aware-scheduling</a>. GitHub repository.</p>]]></content:encoded>
            <enclosure url="https://www.compute-gardener.com/blog/images/legoFlowerGarden.jpg" length="0" type="image/jpg"/>
        </item>
        <item>
            <title><![CDATA[Simplifying Carbon-Aware Computing in a Complex World]]></title>
            <link>https://www.compute-gardener.com/resources/blog/introducing-compute-gardener</link>
            <guid isPermaLink="false">https://www.compute-gardener.com/resources/blog/introducing-compute-gardener</guid>
            <pubDate>Tue, 11 Mar 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[Introducing Compute Gardener]]></description>
            <content:encoded><![CDATA[<p>Infrastructure optimization is drowning in complexity. DevOps teams juggle multiple priorities—maintaining five 9's of uptime, controlling costs across hybrid environments, scaling efficiently—all while facing pressure to reduce carbon footprints without clear pathways to do so.</p>
<h3>The Unseen Challenges of Modern Infrastructure</h3>
<p>Today's reality:</p>
<ul>
<li><strong>Complex Hybrid Environments</strong> make consistent optimization nearly impossible</li>
<li><strong>Siloed Decision Making</strong> separates cost and sustainability goals</li>
<li><strong>Missing Data</strong> forces teams to operate on approximations</li>
<li><strong>Signal Integration Gaps</strong> leave scheduling systems blind to carbon intensity and pricing fluctuations</li>
<li><strong>Optimization Guilt</strong> haunts teams who know they should optimize carbon but lack actionable tools</li>
<li><strong>Accelerating Growth</strong> in data centers means emissions will only increase without intervention</li>
</ul>
<h3>Introducing Compute Gardener</h3>
<p>Within hours, your workloads can begin responding to real-world conditions - automatically shifting to times when your region's carbon intensity is lower or when electricity prices drop during off-peak hours.</p>
<p>This delivers immediate impact on both carbon emissions and costs without requiring you to rearchitect your systems or compromise performance. Our <a href="https://www.compute-gardener.com/solutions/open-source-scheduler">open-source scheduler</a> integrates seamlessly with your existing Kubernetes infrastructure, allowing for controlled, gradual adoption.</p>
<h3>Empowering Teams with Real-Time Insights</h3>
<p>With Compute Gardener, infrastructure teams gain:</p>
<ul>
<li><strong>Visibility</strong> into energy consumption patterns across workloads and nodes</li>
<li><strong>Control</strong> through namespace-level energy budgets with automated notifications</li>
<li><strong>Confidence</strong> from data-driven scheduling decisions based on methodologies aligned with Green Software Foundation guidelines</li>
<li><strong>Flexibility</strong> to optimize workloads based on their specific characteristics</li>
<li><strong>Value Creation</strong> potential through energy savings as carbon credits</li>
</ul>
<h3>From Complexity to Action</h3>
<p>What makes Compute Gardener different:</p>
<ol>
<li><strong>Immediate Impact</strong>: Begin optimizing workloads within hours</li>
<li><strong>Start Where You Are</strong>: Integrate with existing Kubernetes clusters</li>
<li><strong>Gradual Adoption</strong>: Test with namespace-level policies</li>
<li><strong>Automatic Adaptation</strong>: Respond dynamically to changing conditions</li>
</ol>
<h3>Our Path: Local Optimizations to Global Stewardship</h3>
<p>Compute Gardener is open source because sustainable computing requires collective innovation. While our scheduler delivers immediate value with single-region carbon data, our forthcoming <a href="https://www.compute-gardener.com/solutions/signals-api">Advanced Signals API</a> synthesizes a comprehensive global dataset across:</p>
<ul>
<li>Worldwide carbon intensity variations</li>
<li>Dynamic electricity pricing</li>
<li>Real-time cloud infrastructure costs</li>
</ul>
<p>This enables both temporal optimization (when to run workloads) and spatial optimization (where to run them). Beyond optimization, we're also exploring how to transform saved energy—"nega-watts"—and mitigated carbon emissions—"nega-tons"—into validated carbon credits. This represents a fundamental shift: from sustainability as a cost center to sustainability as a value creator and potential revenue stream.</p>
<h3>Join the Movement Toward Sustainable Computing</h3>
<p>The path to sustainable infrastructure doesn't need to be through massive one-time changes—it can begin with accessible tools that enable continuous improvement. Compute Gardener provides these tools today, whether you're taking your first steps toward carbon-aware computing or ready to transform your entire approach to infrastructure.</p>
<p><a href="https://github.com/elevated-systems/compute-gardener-scheduler">&#x3C;> GitHub Repo</a> | <a href="https://www.compute-gardener.com/resources/documentation">⚡ Explore Use Cases &#x26; Docs</a> | <a href="https://www.compute-gardener.com/contact">💃🏾 Connect with Our Team</a></p>
<p>Whether you're looking to reduce operational costs, optimize infrastructure efficiency, or prepare for future carbon markets, we're here to help. Our <a href="https://www.compute-gardener.com/solutions/consulting-services">consulting services</a> team can guide you through implementation, from initial assessment to ongoing optimization.</p>
<p>Let's build more efficient computing infrastructure together—where cost savings and sustainability go hand in hand.</p>
<hr>
<p>Photo by <a href="https://unsplash.com/@koorenny?utm_content=creditCopyText&#x26;utm_medium=referral&#x26;utm_source=unsplash">Robert Koorenny</a> on <a href="https://unsplash.com/photos/red-flowering-plant-garden-3oAQ6rYm1Yg?utm_content=creditCopyText&#x26;utm_medium=referral&#x26;utm_source=unsplash">Unsplash</a></p>]]></content:encoded>
            <enclosure url="https://www.compute-gardener.com/blog/images/robert-koorenny-3oAQ6rYm1Yg-unsplash.jpg" length="0" type="image/jpg"/>
        </item>
    </channel>
</rss>