mercoledì 20 settembre 2023

[English] DMVCFramework Gotcha #1: Object Pool explained

 One aspect related to the performance of an application that is often overlooked is the overhead in the execution of specific tasks. Overhead is influenced by various factors. One of these factors, in the context of OOP (Object-Oriented Programming), is the time it takes to create an object: when we create an object, the process of creation and initialization can be more or less time-consuming depending on the complexity of the object and the initialization process of its attributes. The repeated creation and destruction of this object negatively impact the runtime of both the individual process and the entire application as a whole.

One possible solution to this problem would be to have pre-created objects available, for which we do not have to worry about their lifecycle.

One of the Design Patterns belonging to the category of Creational Design Patterns is the Object Pool. According to its definition:

The Object Pool is a creational design pattern, which is one of those patterns applicable to resolving performance issues related to the initialization process of the components (classes) that make up our system.

The underlying concept of the Object Pool can be summarized by describing a process in which a client, in need of an instance of a class, requests it from the Pool. The Pool, upon the request, 'checks' if it has an instance of that class available to fulfill the request. If the instance is available in the pool, it is returned; if the instance is not available, the Object Pool, which knows the method for creating the instance, creates a new one and returns it.

When the client finishes using the obtained instance, it returns that instance to the Pool, which does not destroy it but makes it available for future requests.

This process is cyclical and, in the best case scenario, helps reduce the overhead derived from creating an instance when it is already present in the pool.

DMVCFramework, the RESTful Framework, JSON-RPC, and ActiveRecord for Delphi maintained by Daniele Teti and the DMVCFramework team, has many small but important features that may be lesser-known. One of these is the implementation of the ObjectPool.

The unit MVCFramework.ObjectPool.pas, present in DMVCFramework, defines a class that implements the Object Pool as the pattern defines it:

```delphi

TObjectPool<T: class, constructor> = class(TInterfacedObject, IObjectPool<T>)

```

The (generic) class TObjectPool implements the IObjectPool<T: class, constructor> interface. IObjectPool requires the implementation of two specific methods for pooling:

```delphi

function GetFromPool(const RaiseExceptionIfNotAvailable: Boolean = False): T;

procedure ReleaseToPool(const Obj: T);

```

`GetFromPool()` is called to obtain an object from the Pool, and `ReleaseToPool()` is called to release and return the object instance to the Pool.

An instance of the TObjectPool class is obtained by invoking the class function `CreatePool()` of the TPoolFactory class, defined as follows:

Note the `Factory: TFunc<T>` parameter of `CreatePool()`: it represents the constructor of the class that specializes the pool. It will be used by the pool when it receives a request and no instances are available.

At this point, I will show in the following code an example of how this is applied:

1) Define a pool for the TClientDataset class:

           2) Utilizziamo l'istanza:

With these simple instructions, we have delegated the creation and management of the lifecycle of our objects to the Pool.

To complete this introduction, I would like to draw attention to two features of the Object Pool present in DMVCFramework:

- The Pool has a size: POOL_SIZE indicates the maximum number of instances maintained in the pool (however, instances consume memory!)

- A thread is implemented; it periodically cleans the pool of instances based on the configured Shrink values.

To conclude, it's worth noting that there is also the unit MVCFramework.IntfObjectPool, which similarly implements an ObjectPool for interfaces. 


#codinglikeacoder

sabato 16 settembre 2023

Lezione della settimana #1

 In questo sabato mattino, ho ancora in testa il progetto al quale sto lavorando. L'averlo ancora in testa è per me sintomo del fatto che non è ancora terminato e che quel che c'è da fare non è completamente definito nel mio cervellino.

Una riflessione l'ho fatta anche su ciò che questa settimana mi ha 'lasciato'.

Questa settimana ho imparato una (nuova, forse saputa e risaputa ma spesso dimenticata) lezioncina:

"basa quel che fai su ciò che è e non su ciò che potrebbe essere"

Sipario.

#codinglikeacoder

 

martedì 29 agosto 2023

DMVCFramework Gotcha #1: Object Pool explained

Uno degli aspetti relativi alle performance di un applicativo che spesso non viene attenzionato, è l'overhead nell'esecuzione di specifici task.
L'overhead è influenzato da diversi fattori. Uno di questi, in ambito OOP,  è il tempo di creazione di un oggetto: quando creiamo un oggetto, il processo di creazione e inizializzazione può risultare più o meno lungo in funzione della complessità dell'oggetto e del processo di inizializzazione dei suoi attributi. La ripetuta creazione e distruzione di questo oggetto, influenza negativamente il tempo di runtime di tutto il singolo processo e dell'intera applicazione nel suo complesso.

Una possibile soluzione a questo problema, sarebbe quella di avere a disposizione oggetti già creati e per i quali non dobbiamo preoccuparci del loro ciclo di vita.

Uno dei Design Patterns appartenente alla categoria dei Creational Design Pattern, è l'Object Pool.
Dalla sua definizione:

l'Object Pool è un creational design pattern, ovvero uno di quei pattern applicabile per la risoluzione di problematiche di performance legate al processo di inizializzazione delle componenti (classi) di cui il nostro sistema si compone.

Il concetto alla base dell'Object Pool si può sintetizzare descrivendo un processo durante il quale un client, che necessita una istanza di una classe, chiede al Pool di fornirgliela. Il Pool, alla richiesta, 'verifica' se ha una istanza di detta classe disponibile per soddisfare la richiesta. Se l'istanza è disponibile nel pool, viene restituita; se l'istanza non è disponibile, l'Object Pool, che conosce il metodo utile alla creazione dell'istanza, ne crea una nuova e la restituisce.
Quando il client termina l'utilizzo dell'istanza ottenuta, la restituisce al Pool che non la distrugge ma la rende disponibile per le future richieste.

Questo processo è ciclico e permette, nel migliore dei casi, di abbattere l'overhead derivato dalla creazione dell'istanza quando questa è già presente nel pool.

DMVCFramework, il Framework RESTfulJSON-RPC e ActiveRecord per Delphi mantenuto da Daniele Teti e il team di DMVCFramework,  ha tante piccole, ma importanti, features forse poco conosciute. Una di questa è l'implementazione dell'ObjectPool.

La unit MVCFramework.ObjectPool.pas presente in DMVCFramework definisce una classe che implementa l'Object Pool così come il pattern lo definisce:

TObjectPool<T: class, constructor> = class(TInterfacedObject, IObjectPool<T>)

La classe (generica) TObjectPool, implementa l'interfaccia IObjectPool<T: class, constructor>
IObjectPool richiede l'implementazione di due specifici metodi per il pooling:

function GetFromPool(const RaiseExceptionIfNotAvailable: Boolean = False): T;
procedure ReleaseToPool(const Obj: T);

GetFromPool() è invocata per ottenere un oggetto dal Pool; ReleaseToPool() è invocata per rilasciare e restituire l'istanza dell'oggetto al Pool.

L'istanza della classe TObjectPool è ottenuta invocando la class function CreatePool() della classe TPoolFactory definita così:

Da notare il parametro Factory : TFunc<T> della CreatePool(): esso rappresenta il costruttore della classe che specializza il pool. Esso sarà utilizzato dal pool quando riceverà una richiesta e non vi saranno istanze disponibili.

A questo punto, mostro nel codice che segue, l'applicazione di quanto descritto con un esempio:

1) Definiamo un Pool per la classe TClientDataset:

           2) Utilizziamo l'istanza:

Con queste semplici istruzioni, abbiamo delegato al Pool la creazione e la gestione del ciclo di vita dei nostri oggetti.

A completamento di questa introduzione, pongo l'attenzione su due caratteristiche dell'Object Pool presente in DMVCFramework:
 - Il Pool ha una dimensione: POOL_SIZE indica il numero massimo di istanze mantenute nel pool (le istanze, comunque, occupano memoria!)
 - E' implementato un thread che periodicamente interviene per ripulire il pool da istanze in funzione dei valori di Shrink impostati.

Per completare, è utile sapere che esiste anche la unit MVCFramework.IntfObjectPool che in maniera analoga implementa un ObjectPool per le Interfacce.

#codinglikeacoder



giovedì 3 agosto 2023

PostgreSQL e le variabili di sessione

Nel migrare un Database Firebird ad uno PostgreSQL, mi sono trovato a dover fare il porting di stored procedure che fanno uso di variabili di contesto, definite in Firebird con le istruzioni SQL :

rdb$set_context('USER_SESSION', 'User_id', 1);
rdb$get_context('USER_SESSION', 'User_id');


Anche PostgreSQL permette di poter definire variabili legate alla sessione, con le seguenti istruzioni SQL:

set foo.username to ''flavio''  per poter definire la nuova variabile 
select current_setting(''foo.username '')  per recuperarne il valore.

Lo scope della variabile creata è limitata alla sessione: alla chiusura della sessione, la variabile non sarà più accessibile. Ed essendo una variabile il cui scope è legato alla sessione, non sarà accessibile a sessioni differenti da quella che l'ha creata.

Per fare un piccolo test, ho creato un progettino in Delphi che, eseguito due (o più volte), permette di definire una nuova variabile legata alla sessione durante la quale sono connesso al database.

Da questo link è possibile scaricare il progetto: Progetto Delphi

Dopo aver creato il vostro DB denominato mydb, mandate in esecuzione due istanze di esso contemporaneamente e provate voi stessi a verificare l'isolamento della variabile creata nell'ambito della sessione.


#codinglikeacoder




venerdì 1 luglio 2022

Profiling

    Spesso è importante capire non solo il perchè il nostro applicativo software è lento, poco performante, pesante nell'esecuzione di uno o più task. E' necessario capirne il quando, il  quanto e il dove.

E' pratica comune aprire il nostro editor, seguire riga per riga il codice del nostro algoritmo in debug e provare a risolvere quello che è, o ci sembra, il problema che determina il rallentamento del nostro applicativo software.

I più allenati, coloro che hanno una esperienza tale nel vedere quel che noi magari non vediamo, riescono a scovare più o meno facilmente, istruzioni e/o porzioni di codice che per la loro natura implementativa, hanno un apporto di complessità da attenzionare. E che per il modo in cui questi costrutti sono (erroneamente) impiegati, influenzano negativamente il nostro codice e di conseguenza il nostro applicativo in fase di esecuzione.

A naso, capirne il quando può sembrare semplice: "quando viene eseguita la procedura X, è più lento rispetto a quando è eseguita la procedura Y". Allora, debugghiamo la procedura X e cerchiamo di venirne a capo. In questo modo abbiamo anche dato probabilmente una risposta anche al dove: nella procedura X.

Ma è vero?
Può darsi. A volte si, altre no. Spesso, no.
Però, e c'è un però, potrebbe anche essere che questa lentezza si manifesti nell'ambito di esecuzione di una procedura più complessa. O che la lentezza della nostra procedura, è frutto di lentezze derivanti da procedure e funzioni che da essa sono eseguite per il compimento del task.

Una analisi strumentale delle performance del nostro applicativo software, ci permette di analizzare in maniera oggettiva, le criticità insite nel nostro codice; dandoci altresì, un grosso aiuto nel dare le risposte sul quando, quanto e dove le criticità si manifestano.
ProDelphi è uno di quei tool che ci permette di profilare il nostro codice sorgente, eseguirlo ed ottenere misurazioni relative alla complessità intesa come percentuale di runtime di ogni metodo e tempo di esecuzione dello stesso.


Grazie al report generato da ProDelphi, è possibile analizzare le performance dei singoli metodi (colonne in rosso) o dei metodi come 'sommatoria' di metodi childs necessari alla esecuzione del task (colonne in blu).
Dal report è possibile rispondere alle nostre domande sul dove: il nome del metodo; il quanto: dal numero di Calls e dal tempo di RunTime RT-SUM.

Per conoscere il dove, è interessante l'analisi del report di dettaglio di ogni metodo:


con esso siamo in grado di analizzare da dove provengono le chiamate al metodo in esame (metodi in verde) e quali metodi invoca il metodo in esame durante la sua esecuzione (metodi in blu). Per ognuno di essi, abbiamo informazioni circa il numero di invocazioni e il tempo di esecuzione.
A completamento dell'informazione esposta con questo grafico, abbiamo una piccola view di fianco nella quale è rappresentata la Critical Path, ovvero il Path più complesso in termini di esecuzione che ha nel nostro metodo in esami la radice.

Per informazioni su ProDelphi, è possibile visitare il sito web: https://www.prodelphi.de/index.html

#CodingLikeACoder


lunedì 27 giugno 2022

Coding like a coder

Quando mi sono trovato a dover dare 'un nome' a questo mio spazio, a questo mio BlogNotes, non ho avuto dubbi: Coding Like a Coder.

Coding Like a Coder.

Non è stata una scelta dettata dall'autoreferenzialità. Mi interessava, invece, esprimere il mio stato d'animo in quel momento. E in quel momento riflettevo sul fatto che stavo entrando in una 'dimensione' nuova, dove la mia fame di conoscenza, di esperienza, di crescita umana e professionale, potessero avere libero sfogo. 

Il coding oggi è alla portata di tanti (di tutti?). Fortunatamente.

Essere un buon coder non è altrettanto facile.

Cosa vuol dire essere un buon coder? E chi può dirlo...
Magari un giorno, quando lo sarò, potrò offrirne una definizione ;)

[English] DMVCFramework Gotcha #1: Object Pool explained

 One aspect related to the performance of an application that is often overlooked is the overhead in the execution of specific tasks. Overhe...