27 ott 2010

Process Killer

Quando un programma va in crash la colpa viene attribuita sempre al programmatore. Mentre quando un programma si blocca, o è troppo lento, è di certo per qualche misfatto dell'amministratore di sistema. Anche se magari il programma è scritto con i piedi ed è propenso all'inchiappettamento di tutti i server su cui gira.

Per ristabilire un po' di giustizia divina, ho pensato di killare senza pietà tutti i processi che utilizzano ferocemente la CPU per più di un determinato tempo. Metodo barbaro, ma molto in voga negli Unix dei vecchi tempi... e non solo.

Naturalmente nel mio caso si tratta di processi che dovrebbero essere molto leggeri ma per qualche strana ragione si incastrano e finiscono per utilizzare il processore a pieno regime, infastidendo anche tutti gli utenti di programmi buoni e gentili.

Come punto di partenza, direi di dare un'occhiata all'output del comando pslist, che lista tutti i processi in esecuzione su di una macchina (locale o remota, a patto di avere i privilegi necessari):

pslist v1.29 - Sysinternals PsList
Copyright (C) 2000-2009 Mark Russinovich
Sysinternals

Process information for ER-MEJO:

Name                Pid Pri Thd  Hnd   Priv        CPU Time    Elapsed Time 
Idle                  0   0   2    0      0    23:05:50.623     0:00:00.000
System                4   8 114 4338     52     0:11:32.114    28:42:03.487
smss                252  11   3   30    340     0:00:00.171    28:42:03.487
csrss               348  13   9 1033   2744     0:00:06.645    28:41:51.132
wininit             416  13   3   79    992     0:00:00.093    28:41:50.414
explorer           4448   8  36 1252  69768     0:07:39.797    28:41:04.882
iexplore           3772   8  13  382   7172     0:00:04.539     3:14:05.766
iexplore           5788   8  22  704  97632     0:05:51.345     3:14:02.648
PsList             4136  13   1  151   1980     0:00:00.187     0:00:00.172

le cui colonne interessanti sono le prime due (nome del process e PID) e le ultime due:

Elapsed Time: tempo totale di esecuzione del processo
CPU Time: tempo effettivamente utilizzato dal processo

ad esempio explorer è in esecuzione da 28 ore e 41 minuti, e durante questo periodo ha utilizzato la cpu per 7 minuti e 39 secondi. Proviamo a rilanciare il psexec e a vedere che cosa succede:

Name                Pid Pri Thd  Hnd   Priv        CPU Time    Elapsed Time 
Idle                  0   0   2    0      0    23:06:42.540     0:00:00.000
System                4   8 114 4342     52     0:11:32.426    28:42:33.493
smss                252  11   3   30    340     0:00:00.171    28:42:33.493
csrss               348  13   9 1050   2744     0:00:06.645    28:42:21.138
wininit             416  13   3   79    992     0:00:00.093    28:42:20.420
explorer           4448   8  42 1295  71484     0:07:40.234    28:41:34.888
iexplore           3772   8  13  389   7600     0:00:04.617     3:14:35.772
iexplore           5788   8  23  716  95520     0:05:53.513     3:14:32.654
PsList             1792  13   1  151   1988     0:00:00.171     0:00:00.156

il comando è stato lanciato circa 30 secondi dopo il primo, ed infatti tutto gli Elapsed Time sono aumentati circa di 30 secondi, processo PsList escluso ma se osserviamo bene si tratta di un nuovo processo con un nuovo PID.

Anche la colonna CPU Time è variata per alcuni processi, e se dividiamo il delta del CPU Time per il delta dell'Elapsed Time possiamo ottenere... la percentuale di utilizzo del processore di questo processo relativamente la periodo di tempo intercorso tra i due lanci del comando psexec.

Da notare che se la macchina dispone di più processori nel Task Manager di Windows vedremo la percentuale riferita a tutte le CPU: un processo che gira su di un singolo processore non potrà quindi superare il 25% di CPU se la macchina dispone di 4 processori.

Con il comando psexec invece non ci dobbiamo preoccupare del numero di processori che ha la macchina: il tempo di CPU utilizzato diviso il tempo di CPU avuto è disposizione può variare da zero a uno ed è l'utilizzo effettivo del signolo processore.

Ho scritto questo codice in Python che controlla ad intervalli regolari un elenco di server, e che giustizia tutti i processi che durante questo periodo di tempo hanno consumato più del 90% della propria CPU:

from __future__ import division
import subprocess
import re
import time

word = dict()
pausa = 30
servers = ('citrix01', 'citrix02', 'citrix03', 'server', 'server-2')

def milliSeconds(time):
  tm = re.match("(\d*)\:(\d*)\:(\d*)\.(\d*)", time)
  if tm:
    return long(tm.group(1)) * 60*60*1000 + long(tm.group(2)) * 60*1000 + long(tm.group(3)) * 1000 + long(tm.group(4))
  else:
    return 0

def getProcess(server, nome):
  pslist = subprocess.Popen('"c:\program files\utils\pslist.exe" \\\\' + server + ' ' + nome, shell=False, stdout=subprocess.PIPE)

  for line in pslist.stdout:
    proc = re.match("^(\w+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+([\w\:\.]+)\s+([\w\:\.]+)", line)
    if proc:
      serverPid = server + '.' + proc.group(2)
      if serverPid in word:
        if (milliSeconds(proc.group(7))-milliSeconds(word[serverPid][1]))/(milliSeconds(proc.group(8))-milliSeconds(word[serverPid][2]))>0.90:
          subprocess.Popen('"c:\program files\utils\pskill.exe" \\\\' + server + ' ' + word[serverPid][4])
      else:
        if proc.group(1) <> "Idle" and proc.group(1) <> "System":
          word[serverPid] = [proc.group(1), proc.group(7), proc.group(8), server, proc.group(2)]

def main():
  while True:
    for server in servers:
      getProcess(server, 'winword')
      time.sleep(pausa)

if __name__ == "__main__":
    main()

da sistemare per bene... e da usare con opportuna cautela!

25 ott 2010

QR Code

Bella l'idea di utilizzare codici a barre a due dimensioni, detti Codici QR, per memorizzare vari tipi di informazioni comprese URL:


chissà se in casa Google si stanno attrezzando per interpretare questi codici ed includerli nel PageRank?
E simpatica anche l'idea di Semapedia.org che propone di linkare il mondo fisico a quello virtuale!

Ma... cliccare su link a caso su di un browser non è mai una stata buona idea. Non è che un giorno tutto ciò comporterà qualche problema di sicurezza? O_o
Meglio pensarci per tempo, che non si sa mai!

Dati oggettivi ed interpretazione

Riguardo ai grafici che riportano l'andamento delle temperature della terra e che vengono presentati al grande pubblico, una cosa importante da sapere è che per ottenerli non è sufficiente inserire tutti i dati a disposizione su di un foglio Excel, cliccare su "Inserisci Grafico", e vedere che cosa ne viene fuori.
I grafici che vediamo sono il risultato di anni di analisi e pulizia.

Mi ricordo un fatto curioso e poco conosciuto, e cioè che tutti i grafici delle temperature degli ultimi anni presentavano un rapido aumento intorno alla metà degli anni 40, seguiti da una altrettanto rapida diminuzione.
Questa variazione era insolita, gli scienziati l'hanno considerata come un dato sporco o una anomalia, ed hanno deciso di "eliminarla".

Tutti i grafici ufficiali sono pertanto stati ripuliti e non presentano questo andamento.

Il procedimento seguito dagli scienziati, naturalmente, è corretto: i dati grezzi sono per loro natura pieni di sporchi, errori, rumore... ed il loro compito è di riuscire ad isolare il vero andamento delle temperature escludendo tutte le sporcizie; il picco in questione è stato isolato perché "stonava" e non pareva avere spiegazione logica, tuttavia eliminare dei dati ad intuito, senza sapere bene il perché, è sempre una sconfitta.

Leggevo su Le Scienze di Aprile 2009 un articolo in cui si dava finalmente una spiegazione a questo picco anomalo.
Da una analisi più approfondita si è visto che l'aumento riguardava infatti le temperature dei mari. Durante gli anni della guerra le navi di rilevazione erano soprattutto statunitensi mentre le navi internazionali avevano diminuito le rilevazioni.

Nelle navi internazionali la temperatura delle acque veniva rilevata tramite secchi calati in acqua che si raffreddano se portati in superficie, mentre nelle navi statunitensi si misurava la temperatura dell'acqua di raffreddamento dei motori, che è più calda della vera temperatura del mare.

Le temperature, naturalmente, erano già state corrette per tenere conto di questo fatto, ma dopo questo studio si è visto che la correzione da applicare non era precisa e doveva essere modificata.

Da un lato è stato dimostrato che l'intuizione è stata esatta e che quindi bene avevano fatto gli scienziati ad eliminare questo dato.

Da un altro punto di vista significa che anche la scienza, pur con dati assolutamente oggettivi a disposizione, è sempre e comunque soggetta all'intuito ed all'interpretazione umana.

Scegliere i colori: programmatori e buon gusto!

La scorsa settimana cercavo un paio di mensole colorate da abbinare ad un mobiletto da mettere in sala. Non trovando nulla di interessante ho provato a chiedere un parere ad un dipendente Ikea, il quale mi ha mostrato delle mensole più larghe rispetto al mobiletto, con un altro spessore, e di colore simile ma diverso.

Credo che i programmatori, quando devono scegliere i colori per i propri programmi o per le pagine web, siano come i dipendenti Ikea: completamente privi di ogni buon gusto.

Capita spesso di vedere utilizzate combinazioni estreme di colori: serve un rosso, un verde, od un blu? Niente di più semplice, si sceglie un buon #ff000 per il rosso, un #00ff00 come verde, e per finire un buon blu #0000ff:


ma questi colori sono pesanti, difficili da combinare, ed assolutamente stonati. La prima regola da ricordare è tutte le combinazioni di colori più estreme devono sempre essere evitate!

Molto meglio utilizzare qualche combinazione più leggera, come ad esempio questa con codice #74A697, #FC8626 e #15766F:


Questi colori stancano di meno e si combinano più facilmente. Ma come scegliere una buona palette di colori?

Un grafico probabilmente non ha nemmeno bisogno di porsi questa domanda, ma un trucco che può usare anche un non grafico consiste nello scegliere una foto colorata, ed estrarre da essa una combinazione di colori che ci piace:


prendiamo un po' della cabina telefonica... ed un altro po' del taxi giallo... ecco qui i nostri amici #e02a2f, #f6d06d e #fbab20:


che possono essere combinati in questo modo:

Data Euribor 1 mese Euribor 2 mesi Euribor 3 mesi Euribor 6 mesi
18 ottobre 2010 0,78%1,00%1,22%1,49%
19 ottobre 2010 0,79%1,01%1,23%1,50%
20 ottobre 2010 0,81%1,02%1,24%1,51%
21 ottobre 2010 0,82%1,03%1,25%1,51%
22 ottobre 2010 0,82%1,03%1,25%1,52%

Naturalmente è solo un esempio, ma come punto di partenza va sempre bene.
Poi magari... un giorno lontano... sistemerò anche i colori di questo blog!

15 ott 2010

Negare Group Policy ad un utente o gruppo

Applicare una policy di dominio ad un numero ristretto di utenti è molto semplice: nella sezione Security Filtering del tab Scope si seleziona l'elenco dei gruppi a cui tale policy va applicata:


ma per applicare una policy a tutti tranne ad un singolo utente? Gestire il tutto con i gruppi è possibile, ma spesso complicato. Bisogna quindi ricorrere ad un barbatrucco!

Ci spostiamo nel tab Delegation, aggiungiamo l'utente (od il gruppo) da escludere, e nelle proprietà avanzate togliamo i permessi di lettura della policy:


See you soon!