SPEED UP your code 

FOR THE PLANET

Carsten Windler

Grafix NewRelic

only bits and bytes?

55,7

Billion electronic devices by 2025

57

Million tonnes of electronic waste in 2021

57

~4%

IT's share of total greenhouse gas emissions

~2%

Share of data centres in global
energy consumption

Green Software Engineering

Green Coding

SUSTAINABLE IT

GREEN IT

GREEN SOFTWARE ENGINEERING

SHIFT

RETHINK

REDUCE

REDUCE

PERFORMANCE IN MIND

My Goodness

Why Didn't I Think of That?

How to not do CSV imports:

  1. Load the whole CSV file into memory
  2. Create a Model from every row
  3. Iterate over the Collection of Models
  4. Do some super slow calculations
  5. Use the Model to save the data
  6. ...?
  7. Timeout

?

Let's optimize some code!

class StringPositionBench
{
    public function benchStrContains()
    {
        str_contains('string contains PHP', 'PHP');
    }

    public function benchPregMatch()
    {
        preg_match("/php/i", 'string contains PHP');
    }
}

?

AI SUPPORT

$resultArray = [];

for ($i = 0; $i <= 10000; $i++) {
    $resultArray[] = sprintf('%s %d', trans('row'), $i);
}

// Time (seconds): 0.45
// Memory Peak (MB): 80.65

?

?

REDUCE FUNCTION CALLS

$resultArray = [];
$transRow = trans('row');

for ($i = 0; $i <= 10000; $i++) {
    $resultArray[] = sprintf('%s %d', $transRow, $i);
}

// Time (seconds): 0.015 (=> 0.03x)
// Memory Peak (MB): 80.65 (=> 1.00x)

!

STRING CONCATENATION

$transRow = trans('row');
$resultArray = [];

for ($i = 0; $i <= 10000; $i++) {
    $resultArray[] = $transRow . ' ' . $i;
}


// Time (seconds): 0.007 (=> 0.48x)
// Memory Peak (MB): 52.64 (=> 0.65x)

!

Preallocate array

$transRow = trans('row');
$resultArray = new SplFixedArray(10001);

for ($i = 0; $i <= 10000; $i++) {
    $resultArray[] = $transRow . ' ' . $i;
}

// Time (seconds): 0.0064 (=> 0.94x)
// Memory Peak (MB): 52.14 (=> 0.99x)

!

OVERALL

$transRow = trans('row');
$resultArray = new SplFixedArray(10001);

for ($i = 0; $i <= 10000; $i++) {
    $resultArray[] = $transRow . ' ' . $i;
}

// From:
// Time (seconds): 0.45
// Memory Peak (MB): 80.65

// To:
// Time (seconds): 0.0064 (=> 0.01x)
// Memory Peak (MB): 52.15 (=> 0.65x)

🎉

PROFILING

What else?

LIFECYCLE OF An HTTP REQUESt

Bootstrap

Business Logic

Finish

up

.env

config

routes

middlewarez!!!1

events

DI container

observers

service providers

validators

Bootstrap

Business Logic

Finish

up

PACKAGES

*Runs/second

Guzzle

14.553*   

Nyholm

17.734*

=> approx. 21% faster!

class DateFormatBench
{
    public function benchDate()
    {
        date('D M d Y H:m:s');
    }

    public function benchDateTime()
    {
        (new \DateTime())->format('D M d Y H:m:s');
    }

    public function benchCarbon()
    {
        (new Carbon\Carbon())->format('D M d Y H:m:s');
    }
}

Carbon has 180+ language files

approx. 3,5 MB

PACKAGE Footprint

https://carstenwindler.de/green-it/why-phps-carbon-is-bad-for-the-climate/

  • Carbon has 200,000 daily installs
  • 3 MB language files downloaded in vain
  • 200,000 x 3 MB x 365 = 213,687 GB
  • 0.81 kWh/GB of data traffic*
  • 442 gCO2e/kWh*
  • 213,687 GB × 0.81 kWh/GB = 173,086 kWh
  • 173,086 kWh × 442 gCO2e/kWh = 76,504,219 gCO2e

 

70+ tCO2e per year

wasted

CARBONS CARBON

* https://sustainablewebdesign.org/calculating-digital-emissions/

fzaninotto/Faker

* https://marmelab.com/blog/2020/10/21/sunsetting-faker.html
https://www.pexels.com/photo/red-sunset-over-water-10276693/

🪦

Over the years, Faker has probably emitted more than 11 Metric tons of CO2 equivalent. Being such a significant contributor to climate change kills me.

François Zaninotto*

composer require everything

ARCHITECTURE

https://unsplash.com/photos/FO2zwDMQzUM

DATABASE

  • Use the right tool for the job
    • SQL
    • NoSQL
    • Key/Value
  • Learn about performance tweaks
    • Indexes
    • Projection
    • Slow query log
    • EXPLAIN statement
    • ORM necessary?

https://unsplash.com/photos/Wpnoqo2plFA

  • Table performance_tests
  • 500,000 rows
  • half of them have some_flag = 1
  • export id, first_name, last_name

EXAMPLE: CSV EXPORT

$stmt = DB::select(
    'SELECT * FROM performance_tests WHERE some_flag = 1'
);

$fp = fopen('/tmp/export.csv', 'wb');

foreach ($stmt as $row) {
    $fields = [
        $row->id,
        $row->first_name,
        $row->last_name,
    ];

    fputcsv($fp, $fields);
}

fclose($fp);
// #1: Raw SQL
DB::select(
   'SELECT * 
   FROM performance_tests WHERE some_flag = 1'
);

// Time: 1.02s
// Memory Peak: 242.71 MB
// #2: Raw SQL + projection
DB::select(
   'SELECT id, first_name, last_name 
   FROM performance_tests WHERE some_flag = 1'
);

// Time: 0.74s
// Memory Peak: 191.62 MB
// #3: Raw SQL + cursor
DB::cursor(
   'SELECT * 
   FROM performance_tests WHERE some_flag = 1'
);

// Time: 0.78s
// Memory Peak: 82.2 MB
// #4: Raw SQL + cursor + projection
DB::cursor(
   'SELECT id, first_name, last_name 
   FROM performance_tests WHERE some_flag = 1'
);

// Time: 0.70s
// Memory Peak: 63.17 MB
Type Time
(s)
Memory Peak
(MB)
Raw SQL 1.02 243
Raw SQL + projection 0.73 192
Raw SQL + cursor 0.78 82
Raw SQL + projections + cursor 0.70 63
$result = PerformanceTest::where('some_flag', '=', 1)->get();

$fp = fopen('/tmp/export.csv', 'wb');

foreach ($result as $performanceTest) {
    $fields = [
        $performanceTest->id,
        $performanceTest->first_name,
        $performanceTest->last_name,
    ];

    fputcsv($fp, $fields);
}

fclose($fp);
// #5: Eloquent
PerformanceTest::where('some_flag', '=', 1)->get();

// Time: 3.74s
// Memory Peak: 378.92 MB
// #6: Eloquent + projection
$result = PerformanceTest::where('some_flag', '=', 1)
    ->select(['id', 'first_name', 'last_name'])
    ->get();

// Time: 3.48s
// Memory Peak: 345.10 MB
// #7: Eloquent + lazy
PerformanceTest::where('some_flag', '=', 1)->lazy();

// Time: 21.63s
// Memory Peak: 55.1 MB
// #8: Eloquent + cursor
PerformanceTest::where('some_flag', '=', 1)->cursor();

// Time: 4.14s
// Memory Peak: 85.47 MB
// #9: Eloquent + Collection filter
PerformanceTest::get()->where('some_flag', '=', 1);

// Time: 7.77s
// Memory Peak: 705.52 MB
PerformanceTest::where('some_flag', '=', 1)->get();
Type Time
(s)
Memory Peak
(MB)
Eloquent 3.74 379
Eloquent + projection 3.48 345
Eloquent + lazy 21.63 55
Eloquent + cursor 4.14 85
Eloquent + cursor + projection 3.99 66
Eloquent + collection filter 7.77 705
Type Time
(s)
Memory Peak
(MB)
Raw SQL 1.02 243
Raw SQL + projection 0.73 192
Raw SQL + cursor 0.78 82
Raw SQL + projections + cursor 0.70 63
Type Time
(s)
Memory Peak
(MB)
Eloquent 3.74 379
Eloquent + projection 3.48 345
Eloquent + lazy 21.63 55
Eloquent + cursor 4.14 85
Eloquent + cursor + projection 3.99 66
Eloquent + collection filter 7.77 705

There is so much more...

  • Hosting
  • Cloud services
  • Time
    • Developer
    • CI/CD
    • QA
    • Product manager
    • SEO
    • Customer satisfaction

MONEY

THANK YOU

Carsten Windler

Principal Engineer @

https://www.linkedin.com/in/cwindler

https://carstenwindler.de

https://plana.earth

APIs

Source: Cloudflare

  • Avoid API calls
    • Caching
  • Reduce amount of data
    • Is all information necessary?
  • Split up endpoints
    • GET /users/12
    • GET /users/12/address
  • Specify fields
    • GET /users/12?fields=id,last_name

APIs

https://www.pexels.com/photo/woman-writing-on-whiteboard-3861943/

  • Log only what is necessary
  • Data retention
  • Garbage collectors / log rotation
  • Compression / file formats

https://www.pexels.com/photo/black-trash-bin-with-full-of-trash-3806764/

STorage

CACHING

  • Byte code cache (OPcache)
  • Proxy cache (CDN)
  • HTTP cache (Varnish)
  • Server-side caching (Redis)
  • Client-side caching (Browser)
  • In-Memory-Caching

There are only two hard things in Computer Science: cache invalidation and naming things.

— Phil Karlton

OPcache

  • Check if enabled
    • php.ini
    • rlerdorf/opcache-status
  • Optimize memory usage, e.g.
    • opcache.memory_consumption=256
    • opcache.max_accelerated_files=20000
  • Disable timestamp validation
    • opcache.validate_timestamps=0
    • opcache_reset()

IN-MEMORY CACHING

$cache = [];

for ($i = 1; $i <= 10000; $i++) {
    $randomNumber = random_int(1, 100);

    if (isset($cache[$randomNumber])) {
        $result = $cache[$randomNumber];
    } else {
        $result = sqrt($randomNumber);

        $cache[$randomNumber] = $result;
    }

    echo $result;
}

// Vergleich mit CodeBench

SERVERLESS / Faas

Speed up your code

By Carsten Windler

Speed up your code

How to improve PHP code to emit less carbon. Talk on the PHP Developer Day 2023 in Dresden, 22.09.2023.

  • 165