mardi 2 septembre 2014

CPUID en C : compter les cores

Comment compter le nombre de coeurs du processeur en C ?

Rien de plus simple : en utilisant l'instruction CPUID du processeur. La documentation (à jour, car beaucoup de vieilles informations sont disponibles sur cpuid et sont maintenant érronées du fait de l'évolution...) nous apprend qu'en appelant CPUID en mettant eax à 0xB et ecx à 1 nous permettra de récupérer dans ebx le nombre de coeurs logiques de notre processeur.
On veut donc réaliser un code :

mov eax, 0xb
mov ecx, 1
cpuid
; à cet endroit, ebx contient le nombre de coeurs.

Pour interfacer avec le C en inline on peut écrire quelque chose comme :
asm("movl $0xb, %%eax\n"
        "movl $1, %%ecx\n"
        "cpuid\n"
        "movl %%ebx, %0\n"
        : "=r" (ebx));

printf("Coeurs : %i\n", ebx);
Sur mon CPU, un Intel core i3 avec l'hyperthreading et 2 cores (4 "threads" grâce à HT) on obtient 4 coeurs logiques, si on passe ecx à 0 en paramètre (avec toujours eax = 11) on obtient 2, pour les coeurs physiques du processeur. L'instruction CPUID permet également d'obtenir de nombreuses autres informations précieuses sur le processeur où s'exécute votre programme, comme le support de certaines extensions (MMX, SSE ou AES..) ainsi que des informations sur les caches et la topologie du CPU.

vendredi 25 juillet 2014

Solitons

Les solitons sont un type d'ondes qui apparaissent souvent des équations de propagation non-linéaires et autres phénomènes de fluides. De telles ondes se propagent dans leur milieu sans se déformer, et on peut en modéliser plusieurs de telles sortes que deux solitons rentrent en contact et "fusionnent" en un soliton plus grand pendant un certain temps.

Voir ici et .

Etant donné quelques solutions analytiques à l'équation non-linéaire de KdV on peut modéliser la propagation de quelques solitons en deux dimensions avec OpenGL :








On obtient également des phénomènes de propagation analogues en 3D, avec ici un soliton isolé :



Ou encore 2 solitons en interaction :



mercredi 9 juillet 2014

Diffusion de matière

Soit l'équation de la chaleur à une dimension :

Qui se généralise sans aucun problème avec un laplacien à plusieurs dimensions, et où on néglige le coefficient de diffusion qu'on pose à 1.

Pour la résoudre numériquement sur une grille 2D, on divise le plan en petites cases (N*N), on a un tableau de deux (ou une seule avec un petit calcul) dimensions qui correspondra à la quantité u qui sera diffusée. L'évolution de u sera simplement :

u[i][j] += K*(u[i+1][j] + u[i-1][j] + u[i][j+1] + u[i][j-1] - 4*u[i][j])*4*N

L'implémentation de cette version très simplifiée d'une diffusion donne des résultats assez convaincants, par exemple cette diffusion correspond à la donnée initiale de trois points centraux de densité : 




Voici le résultats obtenu avec comme configuration initiale une barre très dense :




dimanche 9 mars 2014

[CPU] Pipeline

Qu'est-ce qu'un pipeline ?

Le pipeline est une technique implémentée dans un processeur pour optimiser le temps de traitement d'une instruction. En clair il repose sur le principe simple de la chaîne de montage, pour produire plusieurs fois à la suite des objets on peut faire chaque objet d'un coup, un à la suite. Le temps total sera donc le nombre d'objet multiplié par le temps mis pour un seul objet.
Maintenant l'idée est de découper la fabrication de l'objet en plusieurs étapes ou "étages" indépendants, de telle sorte que chaque étage peut fonctionner en même temps que tous les autres et qu'il soit nécessaire de passer par tous les étages inférieurs pour atteindre un étage donné.

Ainsi imaginons un pipeline à 3 étages et 3 objets à concevoir et supposons que le temps mis à chaque étage soit le même : T. L'objet 1 arrive au premier étage du pipeline, pendant ce temps les deux autres objets attendent, une fois l'étape 1 passée, l'objet 1 passe à l'étage 2, libérant ainsi l'étage 1, l'objet 2 est donc placé à l'étage 1, l'objet 3 attend. Ensuite une fois l'étape 2 de l'objet 1 et l'étape 1 de l'objet 2 finies, l'objet 1 passe à l'étage 3, l'objet 2 à l'étage 2 et l'objet 3 à l'étage 1 qui vient d'être libéré. Et ainsi de suite...

Le temps total mis sans pipeline serait par exemple de 3 * 3T soit 9T. Avec pipeline il est seulement de 5T !


L'idée est la même pour le pipeline du CPU, chaque instruction à exécuter est séparée en étages mettant sur ce schéma un cycle d'horloge à être exécutée. Les étapes sont les suivantes le "fetch" (IF pour "Instruction Fetch") qui sépare la commande et les opérandes, le décode (ID pour "Instruction Decode") qui permet de traduire la commande pour la rendre intelligible par les unités du processeur, l'exécution à proprement dit de l'instruction (EX), MEM (Memory) correspond aux opérations post-exécution qui sont exécutées dans la mémoire, par exemple écrire à un certain endroit ou lire une donnée, et enfin le "Write-Back" (WB) finalise l'instruction en mettant à jour les registres avec les résultats.

Ce type de pipeline synchronisé par le front d'horloge du CPU est appelé "pipeline synchrone", il existe un autre type de pipeline appelé "asynchrone" où la mise à jour et les changements d'étages sont effectués via la communication entre les étages.

Le nombre d'étages du pipeline est caractéristique du CPU et est appelé "profondeur du pipeline", la profondeur des pipelines des processeurs modernes est souvent entre 12 et 15 étapes, qui sont des découpages des étapes présentées (fetch, decode..)

Spinlock & Mutex ?

Quelle est la différence entre un mutex et un spinlock ?

Les deux concepts sont quasiment identiques puisque les deux sont des mécanismes de synchronisation.
Quand un thread essaye de lock un mutex, si il réussit, il prend le contrôle de ce mutex et accède aux données partagées, sinon il attend simplement son tour dans une queue.
Le spinlock diffère légèrement : quand un thread essaye de le lock alors qu'il est déjà pris ailleurs, le thread va continuer sans arrêt de réessayer de le lock jusqu'à qu'il en prenne le contrôle, d'où l'idée de "spin" car le thread recommence tout le temps. Un tel mécanisme est très consommateur de cycles de CPU et est généralement inutile sur un système mono-processeur, mais peuvent s'avérer rentable sur des systèmes multi-processeurs.

Cependant il existe également des mutex hybrides, dans les systèmes modernes, si un thread essaye de lock ce mutex et qu'il n'y arrive pas, il ne va pas se mettre en pause et attendre (comme le ferait un thread avec des mutex classiques) mais va spinlock pendant un court instant, et si après cela le mutex n'est toujours pas unlock par le thread, alors il est mis en attente.

[Os] Comment reboot un ordinateur ?

Une question qui peut revenir pour ceux qui s'intéressent au développement des systèmes d'exploitation, à l'assembleur ou qui veulent simplement comprendre le fonctionnement d'un ordinateur.

D'un point de vue de programmeur, il existe une manière décrite dans le manuel d'intel pour les processeurs x86 pour redémarrer l'ordinateur, il faut pour cela générer une "triple fault".
Une triple fault intervient lorsqu'une interruption est générée et qu'une routine (ISR) n'est pas trouvée pour cette interruption. Pour cela il "suffit" de provoquer en toute conscience l'erreur en chargeant en mémoire une table de descripteurs d'interruption (IDT) vide et en générant manuellement une interrupt en appelant "int", l'interruption échoue et le gestionnaire de faute échoue aussi et le CPU provoque un redémarrage.

Cependant en réalité pour redémarrer, étant donné l'implémentation de l'ACPI (Advanced configuration and power interface) pour gérer l'alimentation, les systèmes d'exploitation envoient simplement une instruction de reboot au gestionnaire, la carte-mère se charge de reboot tous les composants et n'est jamais elle-même éteinte.

samedi 8 mars 2014

Malware et mutex

Les mutex sont un mécanisme de protection de données partagées, si deux threads concurrents essayaient d'accéder en même temps (avec le parallélisme d'exécution) à une même donnée, alors la donnée risque d'être corrompue, et le code deviendra buggé.
Pour cela on utilise un mutex afin de "synchroniser" l'accès aux données par les threads, si le thread A veut lire une valeur à une certaine adresse mémoire, il va "vérouiller" (lock) le mutex correspondant, empêchant tout autre thread B tentant de le vérouiller à son tour de continuer son exécution, faire son affaire avec la valeur, et libérer le mutex, afin qu'un éventuel thread B concurrent puisse prendre le contrôle du mutex et utiliser la donnée.

Voilà pour la théorie de programmation concurrente, les malwares multithreadés utilisent également ce système pour éviter d'avoir des problèmes de synchronisation, cependant en plus de cela, les mutex sont utilisés par ces malwares pour éviter d'infecter deux fois la même cible.
En effet le logiciel va au démarrage vérifier si un mutex global est présent sur le système (il identifie le mutex avec un nom spécial), si c'est le cas le programme malveillant s'interrompt car la machine est déjà infectée, sinon il crée ce mutex et continue son infection.

Il est possible d'analyser les mutex (aussi appelés "mutant") présents sur le système afin de vérifier si une machine est infectée ou non par une menace donnée.