17 czerwca 2009

Przyspieszenie aplikacji z Google Perftools

Wielu ludzikom, którzy nie biorą na poważnie optymalizacji lub nie mają z nią potencjalnych problemów na codzień takie pojęcie jak profilowanie bywa długo obce. Mogą tylko się z tego cieszyć, bo w rękach ich bardziej doświadczonych kolegów od profilowania aplikacji spoczywa pewna magiczna moc.

Czasami bywamy pytani o to, jak można coś zrobić szybciej lub napisać tak, aby działało szybciej na tej samej maszynie. W sytuacji w której tematem optymalizacji jest jakiś nieskomplikowany język skryptowy typu Python, PHP, czy Ruby mamy do dyspozycji napisanie modułu w języku C. Zasadniczo te języki są napisane w C (C++) i zakładamy, że moduł napisany w języku źródłowym, w którym napisano dany język będzie szybszy. Sprawa się nieco komplikuje, gdy nie mamy takiego pomostu jak możliwość napisania kodu modułu w kodzie źródłowym języka. Jeszcze częściej nie mamy wpływu na sposób zarządzania pamięcią oraz wielowątkowością w danym języku skryptowym. Posłużę się dla przykładu językiem PHP, który posiada źródłową konwencję nazwaną Zend Engine. Jest to narzucony silnik stworzony poprzez firmę Zend i rozwijany przez deweloperów woluntariuszy na całym świecie. Niestety naleciałości, które ciągną się za nim od wielu lat ograniczają znacząco działanie tak istotnych mechanizmów języka jak wielowątkowość i odśmiecanie pamięci. Język ten w samych swoich źródłach jest pod tym kątem niedojrzały. Inna sytuacja jest w przypadku języka Python i Ruby. Słynna translacja języka Python w samym RPython (Restricted Python) - statycznym podzbiorze Pythona, który można skompilować do kodu bajtowgo Javy, CLR czy C, czyli projekt PyPy. Pozwala na bardzo rozwinięte horyzonty działania, które dla niewiedzących prowadzić mogą do definowania np: własnych zasad odśmiecania pamięci, sposobu działania wielowątkowości i całej gamy innych drobiazgów, które stawiają dość wysoko język Python na podeście :-) Nie znam dokładnie źródeł języka Ruby, ale widziałem, że są czytelne i można po nich wywnioskować, że doruwnuą projektowi takiemu jak Python, ale też zostawiają w tyle PHP Zend Engine.

Rozpisałem się o ogólnym spojrzeniu na źródła powszechnych języków skryptowych, aby naświetlić tylko, że dla niektórych języków temat optymalizacji, czyli profilowania na poziomie źródeł języka jest dość ograniczony. Lecz z kolei są takie języki skryptowe, które można profilować na poziomie wątków oraz zarządzania pamięcią. Projekty w ramach których dość czytelnie to zaprezentowano zawierają materiały dodatkowe. Wspomnę jeszcze, że nasz ulubiony googiel też się podpisuje do takich praktyk i posiada dość spore doświadczenie w tej materii. W soich serwerowniach dobierają procesory oraz z tego co mi wiadomo na farmach maszyn odbywa się również profilowane kompilowanego oprogramowania, aby jak najwięcej wycisnąć. Jest to jedna z nielicznych firm, która używa selekcjonowanych i wygrzewanych partii procesorów Pentium III oraz serwerownie stanowią klastry słabszych maszyn o przewidywalnej mocy obliczeniowej oraz przewidywalnym zużyciu energii. Skoro google udowodniło, że można nie kupować drogich serwerów IBM, czy Suna, czy tez HP jestem zgodny z nimi, że wówczas bez profilowania oraz optymalizacji zarówno hardware a przede wszystkim software nie wiele zdziałamy.

Przechodząc do części praktycznej chciałbym uchylić fragment tajemnicy przyspieszania aplikacji z Google Perftools. Materiał na temat przykładu profilowania znajdziecie tutaj.


Życzę pomyślnej lektury i zapraszam do podzielenia się refleksjami na ten temat.


Materiały dodatkowe:

Mastering the Art of Indexing

High Availability and Scalability Patches from Google

More on using Google Perftools with MySQL


Using the Google Perftools to speed up your MySQL server


Using the Google Perftools to speed up your MySQL server - example

Fast, multi-threaded malloc() and nifty performance analysis tools

Simple HTTP server for use with google-perftools pprof

TCMalloc : Thread-Caching Malloc


prof/PerfTools


This page describes how to setup and use PerfTools.

This CPU profiler used at Google

Spinlock


Practical Concurrency Patterns: Spinlock


Practical Concurrency Patterns: Lock-Free Operations

Spinlock example code

The performance of spin lock alternatives for shared-memory multiprocessors

HP - Spinlock Pool Parameter Summary

.NET Framework Class Library - SpinLock Structure

The Hoard Memory Allocator and Memory Management Studies

Generate Ruby Profiling Charts With Perftools

Profiling Ruby With Google’s Perftools

Distributed Innodb Caching with memcached

InnoDB: Innovative Technologies for Performance and Data Protection

9 czerwca 2009

Stackless Python - jak zrobić mikrowątki na localhost

Dziś zapraszam do kilku prób zrobienia z naszego lokalhosta maszyny z działającymi w tle mikrowątkami Stackless Python, które potrafią dość wiele zdziałać. Aby dowiedzieć się jak wiele polecam przeczytanie artykułu o grze EVE on-line, która bazuje na tym rozwiązaniu.

Ważnym wprowadzeniem będzie teoria na wikipedii dotycząca Distributed computing. Są różne podejścia do reazlizacji wielowątkowości i jej synchronizajci. Zasadniczo doceniam w tym artykule specyficzne, bo posiadające w API dosłownie kilka funkcji. Zaimplementowanych w taki sposób, że aż się miło testuje i wdraża takie rozwiązanie. Oczywiście porównuję tutaj API systemowe np: WINAPI i POSIX THREADS. Jest z tym nieco zabawy w projektowaniu i kodowaniu, dlatego przedstawiam Stackless Python, który może rowiązać więcej problemów niż tylko wymienione niewygody wielowątkowości w naszym systemie operacyjnym.

Okazuje się, że programowanie wielowątkowe na większą skalę wcale nie musi posiadać skomplikowanego API. Projektanci Stackless Python doskonale o tym wiedzieli i uprościli bazowe elementy API do następujących pojęć:

  • Tasklets

  • The Scheduler

  • Channels


Zacznę od bazowego przykładu, który pokazuje, jak rozpocząć zabawę z tą technologią. Do wykonania poniższego kodu będzie potrzebna obecność w naszym systemie pypy-stackless.

Tasklets są podstawowym budulcem dla stackless. Możesz utworzyć zadania tasklet przez dodanie zwykle funkcji lub metody klasy. Stworzony w ten sposób tasklet zostaje dodany do harmonogramu zadań. Zauważ, że kolejka taskletów i nie działaja, dopóki nie nastąpi wywołanie metody stackless.run().
Oto prosta demonstracja:
# example1.py

import stackless

def print_x(x):
print x

stackless.tasklet(print_x)('one')
stackless.tasklet(print_x)('two')
stackless.tasklet(print_x)('three')

stackless.run()

Uruchamianie przykładu oraz rezultaty działania:

$ pypy-stackless example1.py
one
two
three

Scheduler kontroluje kolejność, w jakiej tasklets są uruchamiane. Jeśli po prostu stworzysz kilka taskletów, będą uruchamiane w kolejności, w jakiej zostały utworzone. W ogólnej praktyce będzie to związane ze stworzeniem i wywołaniem dodanych taskletów za każdą iteracją ogólnego mechnizmu obiegu danych.
Zauważ, że gdy wywołujemy stackless.schedule(), aktywnym tasklet zatrzymuje się i ponownie wstrzykuje się do końca schedulera w kolejce, pozwalając następnemu taskletowi uruchomić się. Gdy wszystkie z aktywnych taskletów zostaną uruchomione, następuje przywoływanie pozostałych. To trwa do zakończenia wszystkich aktywnych taskletów. W ten sposób osiągamy wielowątkowość we współpracy z stackless.
Szybka demonstracja:

# example2.py

import stackless

def print_three_times(x):
print "1:", x
stackless.schedule()
print "2:", x
stackless.schedule()
print "3:", x
stackless.schedule()

stackless.tasklet(print_three_times)('first')

stackless.tasklet(print_three_times)('second')

stackless.tasklet(print_three_times)('third')

stackless.run()

Uruchamianie przykładu oraz rezultaty działania:

$ pypy-stackless example2.py
1: first
1: second
1: third
2: first
2: second
2: third
3: first
3: second
3: third



Channels czyli kanały umożliwiają wysyłanie informacji między tasklets. To realizuje dwie rzeczy:

Pozwala to na wymianę informacji między tasklets.
Pozwala to na kontrolę przepływu egzekucji.

Kolejna szybka demonstracja:


# example3.py

channel = stackless.channel()

def receiving_tasklet():
print "Recieving tasklet started"
print channel.receive()
print "Receiving tasklet finished"

def sending_tasklet():
print "Sending tasklet started"
channel.send("send from sending_tasklet")
print "sending tasklet finished"

def another_tasklet():
print "Just another tasklet in the scheduler"

Uruchamianie przykładu oraz rezultaty działania:
$ pypy-stackless example3.py



Recieving tasklet started
Sending tasklet started
send from sending_tasklet
Receiving tasklet finished
Just another tasklet in the scheduler
sending tasklet finished


Kilkoma słowami chciałbym podsumować opisane rozwiązanie w Stackless Python. Po pierwsze ilość dostępnych funkcji w API oraz sposób ich użycia szczególnie zachęca do zgłębiania i używania (4 - 6 funkcji). Zarazem niesamowitym osiągnięciem jest fakt, że tak wielki projekt gry on-line jak EVE bazuje na tak prostym i wydajnym rozwiązaniu.

Zachęcam do opisania swoich doświadczeń ze Stackless Python w komentarzach, chętnie podyskutuję.

Mariały dodatkowe:

Stackless Python Homepage

why stackless

Is Stackless Python for You?

Introduction to Concurrent Programming with Stackless Python

Wątki


http://www.archivum.info/pl.comp.lang.python/2008-03/msg00119.html

http://forum.gamedev.pl/index.php?action=printpage%3Btopic=6678.0


Kurs Pisania OS

Debug pamięci w Linuksie (pamięć od strony technicznej)

Dynamiczne zarządzanie pamięcią w C bez wycieków

Stackless Python - artykuly

CORBA Guru Steve Vinoski on REST, Web Services, and Erlang

6 czerwca 2009

Max/MSP + Arduino - udźwiękowienie głuchej maszyny

W wielu wymiarach mikroprocesorowych odkryć jest też taki, który powoduje, że głucha, cicha i stara zabawka leżąca w szuflkadzie jaką może być system mikroprocesorowy nagle ożywa i wydaje przeróżne - w tym niesamowite - dźwięki. Mam na myśli adaptacje Adruino w wersji MaxMSP.

Z materiału Arduino VS Max/MSP wynika, że najlepszym softem do zabawy będzie Maxduino. Zabawa może polegać na tym, że rozrysowujemy w aplikacji Max wykres działania / połączenia z systmem generatorem/syntezatorem dźwięku i uploadujemy program do naszej zabawki. Dodatkowe interfejsy mile widziane. Diody RGB, klawisze, czujniki natężenia światła i całą resztę można powiązać z syntezowaniem bitów, które sprawią, że na pozór cichy i bezduszny sprzęt nabierze niesamowitego wydźwięku i będzie w stanie nas zaskoczyć brzmieniem np: z gatunku ambient :-)

Oto kilka przykładów zrealizowanych pomysłów:






















Materiały dodatkowe:

http://www.music.mcgill.ca/~gary/306/week5/serial.html

http://www.tigoe.net/pcomp/code/category/category/MaxMSP

http://www.flickr.com/photos/gudmundsson/3234647715/

http://www.soundplusdesign.com/?p=1305

http://www.soundplusdesign.com/?cat=116

http://www.alimomeni.net/node/204

http://blog.soundsorange.net/2006/08/29/arduino-getting-the-usb-version-up-and-running-on-osx-using-pd/

http://ultranoise.es/blog/?p=213