jueves, julio 30, 2009

analizando interfaces de usuario inconscientemente

hoy fui a sacar plata a un cajero link (yo tengo banelco).

Es la primera vez que saco plata en esos cajeros así que no se si todos son iguales pero automáticamente me puse a analizar la interfaz de usuario, me llamo la atención de que si pones 4 números y están bien pasa derecho a la próxima pantalla, no se que hará si los números están mal, habría que probar si poniendo números mal en 5 segundos no hace nada podemos probar muchas combinaciones hasta que pase (no probado).

Pero eso es un detalle nomas, la pantalla de inicio me dio aproximadamente 8 opciones con variaciones mínimas que podrían haber sido movidas a otro submenu, la opción de extracción te pregunta de donde lo queres sacar y cuenta corriente en pesos no esta en ningún extremo si no en el centro a la derecha, los otros diálogos me parecieron también muy llenos de opciones y las opciones que generalmente son las por defecto no están en un lugar constante y visible (por ejemplo siempre arriba a la izquierda o similar).

Por ultimo el cajero te da la plata y el ticket y después te pregunta si queres hacer otra operación o finalizar. Razón por la cual casi me olvido la tarjeta ya que saque la plata, el ticket y como en los otros cajeros la tarjeta te la da antes con una chicharra y una luz es menos factible que te la olvides.

Si soy un colgado olvidador de cosas y pienso giladas pero me di cuenta como el cajero al que voy me simplifica la vida sin que me de cuenta :D.

miércoles, julio 29, 2009

correcciones de problemas de MPI

alguien me paso el tip de que el broadcast de MPI es una operacion colectiva y que no tiene que ir en el rank 0 si no que todos lo tienen que ejecutar ya que tiene el receive implicito, asi que aca los 2 programas corregidos (los que no imprimian los valores de los procesos que no fueran el master).

plus un arreglo en la declaracion de la estructura en el segundo programa.

#include <stdio.h>
#include <mpi.h>

int main (int argc, char** argv) {
int rank, size, value, i;
MPI_Status status;

MPI_Init (&argc, &argv); /* starts MPI */
MPI_Comm_rank (MPI_COMM_WORLD, &rank); /* get current process id */
MPI_Comm_size (MPI_COMM_WORLD, &size); /* get number of processes */

do {
if(rank == 0) {
printf("give me a value: ");
scanf("%d", &value);
}

MPI_Bcast(&value, 1, MPI_INT, 0, MPI_COMM_WORLD);
printf("process %d received %d\n", rank, value);
fflush(stdout);
} while(value >= 0);
printf("negative value, closing\n");

MPI_Finalize();
return 0;
}

#include <stdio.h>
#include <mpi.h>

MPI_Datatype IntDoubleType = 0;

typedef struct {
int value_int;
double value_double;
}IntDouble;

MPI_Datatype create_int_double_type() {
if(IntDoubleType == 0) {
MPI_Aint array_of_displacements[2];
MPI_Datatype array_of_types[2];
int array_of_blocklengths[2];

array_of_displacements[0] = 0;
array_of_types[0] = MPI_INT;
array_of_blocklengths[0] = sizeof(int);

array_of_displacements[1] = sizeof(int);
array_of_types[1] = MPI_DOUBLE;
array_of_blocklengths[1] = sizeof(double);

MPI_Type_struct(1, array_of_blocklengths, array_of_displacements,
array_of_types, &IntDoubleType);
MPI_Type_commit(&IntDoubleType);

}

return IntDoubleType;
}

int main (int argc, char** argv) {
int rank, size, value_int, i;
double value_double;
IntDouble value;
MPI_Status status;

MPI_Init (&argc, &argv); /* starts MPI */
MPI_Comm_rank (MPI_COMM_WORLD, &rank); /* get current process id */
MPI_Comm_size (MPI_COMM_WORLD, &size); /* get number of processes */
create_int_double_type();

do {
if(rank == 0) {
printf("give me an int value: ");
scanf("%d", &value_int);
printf("give me a double value: ");
scanf("%lf", &value_double);
value.value_int = value_int;
value.value_double = value_double;
}

MPI_Bcast(&value, 1, IntDoubleType, 0, MPI_COMM_WORLD);
printf("process %d received %d %lf\n", rank, value.value_int,
value.value_double);
fflush(stdout);
} while(value.value_int >= 0);
printf("negative value, closing\n");

MPI_Finalize();
return 0;
}

sábado, julio 25, 2009

generando funciones dinamicamente (a.k.a generando bytecode a mano)

Este desafio estuvo bueno, alguien en la lista de emesene dijo que para hacer la API de dbus exponiendo los eventos del protocolo (que tienen numero de argumentos variables) necesitaba generar funciones con cantidad de argumentos variables pero que la funcion tenga ese numero fijo, esto significa que si tengo que generar una funcion que recibe 4 argumentos tiene que ser:

def fun(arg0, arg1, arg2, arg3): pass

y no

def fun(*args): pass

ya que la API de dbus usa inspect para determinar el numero de argumentos posicionales

me tomo varias horas sacarlo, buscaba y buscaba y cada vez iba mas a bajo nivel. Hasta que llegue al mas bajo nivel que se puede llegar... generar bytecodes :)

y bue, pelee con eso un buen rato ya que si bien alguna vez jugue haciendo maquinas virtuales de juguete esta era la primera vez contra una en serio.

el resultado es el siguiente:


import dis
import types

def gen(num):
op = dis.opmap.__getitem__
ops = [op('LOAD_GLOBAL'), 0, 0]

for argnum in range(num):
ops.append(op('LOAD_FAST'))
ops.append(argnum)
ops.append(0)

ops.append(op('CALL_FUNCTION'))
ops.append(num)
ops.append(0)
ops.append(op('RETURN_VALUE'))

code_str = ''.join(chr(x) for x in ops)
return code_str

def gen_code(num, global_vars, name='func', filename='magic.py'):
code = gen(num)
varnames = ['arg' + str(x) for x in range(num)]
names = global_vars + varnames

names = tuple(names)
varnames = tuple(varnames)

return types.CodeType(num, num, num, 0, code, (), names, varnames, filename, name, 1, '')

def gen_fun(num, name, func):
code = gen_code(num, [func.__name__], name)
return types.FunctionType(code,{func.__name__: func})

if __name__ == '__main__':
def printer(*args):
print args

f4 = gen_fun(4, 'f4', printer)
dis.dis(f4.func_code)
f4(1,2,3,4)

f1 = gen_fun(1, 'f1', printer)
dis.dis(f1.func_code)
f1('only one arg')

try:
f1(1, 2)
except TypeError:
print 'ok, ok, only one argument'


lo que hace es generar una funcion que recibe N parametros y que lo unico que hace es llamar a otra funcion pasandole esos parametros, lo cual seria algo como:

def fun1(*args): print args

def fun_que_recibe_4_parametros(a,b,c,d): fun1(a,b,c,d)

con lo que si escribimos nuestra funcion en fun1 y creamos las funciones que reciben los distintos parametros con un for tenemos lo que necesitamos :)

la salida de la ejecusion de lo de arriba es:

1 0 LOAD_GLOBAL 0 (printer)
3 LOAD_FAST 0 (arg0)
6 LOAD_FAST 1 (arg1)
9 LOAD_FAST 2 (arg2)
12 LOAD_FAST 3 (arg3)
15 CALL_FUNCTION 4
18 RETURN_VALUE

(1, 2, 3, 4)

1 0 LOAD_GLOBAL 0 (printer)
3 LOAD_FAST 0 (arg0)
6 CALL_FUNCTION 1
9 RETURN_VALUE

('only one arg',)
ok, ok, only one argument


fuentes de inspiracion:

http://pyref.infogami.com/type-code
http://docs.python.org/library/dis.html
http://docs.python.org/library/types
http://docs.python.org/reference/datamodel.html#the-standard-type-hierarchy (la parte de callable types)

lunes, julio 20, 2009

Resolviendo ejercicios de MPI (y tambien en erlang) Parte 4

Sigo molestando con estos problemas, me salte uno que no me daba ganas de resolver y pase al siguiente:

http://www.mcs.anl.gov/research/projects/mpi/tutorial/mpiexmpl/src/ring/C/main.html

Write a program that takes data from process zero and sends it to all of the other processes by sending it in a ring. That is, process i should receive the data and send it to process i+1, until the last process is reached.

la solucion en C salio bastante facil haciendo copypasta de los problemas anteriores y sorprendentemente en este caso los otros procesos si imprimieron a la consola:

#include <stdio.h>
#include <mpi.h>

int main (int argc, char** argv) {
int rank, size, value, i;
MPI_Status status;

MPI_Init (&argc, &argv); /* starts MPI */
MPI_Comm_rank (MPI_COMM_WORLD, &rank); /* get current process id */
MPI_Comm_size (MPI_COMM_WORLD, &size); /* get number of processes */

do {
if(rank == 0) {
printf("give me a value: ");
scanf("%d", &value);
fflush(stdout);
MPI_Send(&value, 1, MPI_INT, rank + 1, 1, MPI_COMM_WORLD);
}
else{
MPI_Recv(&value, 1, MPI_INT, rank - 1, 1, MPI_COMM_WORLD, &status);
printf("process %d received %d\n", rank, value);
if(rank + 1 < size) {
printf("sending to %d\n", rank + 1, value);
MPI_Send(&value, 1, MPI_INT, rank + 1, 1, MPI_COMM_WORLD);
}
fflush(stdout);
}
} while(value >= 0);
printf("negative value, closing\n");

MPI_Finalize();
return 0;
}


la solucion en erlang (tambien robando del ejercicio anterior):

-module(ej5).
-export([run/1]).

run(Total) ->
NextPid = spawn_listeners(Total),
get_values(NextPid).

spawn_listeners(Count) -> spawn_listeners(Count, none).

spawn_listeners(0, NextPid) -> NextPid;
spawn_listeners(Count, LastPid) ->
NextPid = spawn(fun() -> listener(LastPid) end),
spawn_listeners(Count - 1, NextPid).

listener(NextPid) ->
receive
Int ->
io:format("process ~p received ~p~n", [self(), Int]),
if
NextPid /= none ->
io:format("sending to ~p~n", [NextPid]),
NextPid ! Int;
true -> ok
end,
if
Int >= 0 -> listener(NextPid);
true ->
io:format("negative value, closing ~p~n", [self()])
end
end.

get_value(Message, ConversionFun) ->
case io:get_line(Message) of
{error, Reason} -> {error, Reason};
eof -> {error, eof};
Value -> ConversionFun(Value)
end.

get_values(NextPid) ->
case get_value("give me an int value (negative to quit): ", fun(Val) -> string:to_integer(Val) end) of
{error, Reason} ->
io:format("error reading int value (~p)~n", [Reason]),
get_values(NextPid);
{IntValue, _Rest} ->
io:format("sending to ~p~n", [NextPid]),
NextPid ! IntValue,
if
IntValue >= 0 -> get_values(NextPid);
true -> io:format("negative value, closing~n")
end
end.


ejemplo de salida:

$ erl
Erlang (BEAM) emulator version 5.6.5 [source] [async-threads:0] [kernel-poll:false]

Eshell V5.6.5 (abort with ^G)
1> c(ej5).
{ok,ej5}
2> ej5:run(3).
give me an int value (negative to quit): 3
sending to <0.40.0>
process <0.40.0> received 3
sending to <0.39.0>
process <0.39.0> received 3
sending to <0.38.0>
process <0.38.0> received 3
give me an int value (negative to quit): asd
error reading int value (no_integer)
give me an int value (negative to quit): 42
sending to <0.40.0>
process <0.40.0> received 42
sending to <0.39.0>
process <0.39.0> received 42
sending to <0.38.0>
process <0.38.0> received 42
give me an int value (negative to quit): -1
sending to <0.40.0>
negative value, closing
process <0.40.0> received -1
sending to <0.39.0>
ok
negative value, closing <0.40.0>
process <0.39.0> received -1
sending to <0.38.0>
negative value, closing <0.39.0>
process <0.38.0> received -1
negative value, closing <0.38.0>

domingo, julio 19, 2009

Resolviendo ejercicios de MPI (y tambien en erlang) Parte 3

enunciado del problema:

In this assignment, you will modify your arguement broadcast routine to communicate different datatypes with a single MPI broadcast (MPI_Bcast) call. Have your program read an integer and a double-precision value from standard input (from process 0, as before), and communicate this to all of the other processes with an MPI_Bcast call. Use MPI datatypes.

Have all processes exit when a negative integer is read.


aca esta la resolucion en C:

#include <stdio.h>
#include <mpi.h>

MPI_Datatype IntDoubleType = 0;

typedef struct {
int value_int;
double value_double;
}IntDouble;

MPI_Datatype create_int_double_type() {
if(IntDoubleType == 0) {
MPI_Aint array_of_displacements[2];
MPI_Datatype array_of_types[2];
int array_of_blocklengths[2];

array_of_displacements[0] = 0;
array_of_types[0] = MPI_INT;
array_of_blocklengths[0] = 1;

array_of_displacements[1] = 1;
array_of_types[1] = MPI_DOUBLE;
array_of_blocklengths[1] = 1;

MPI_Type_struct(1, array_of_blocklengths, array_of_displacements,
array_of_types, &IntDoubleType);
MPI_Type_commit(&IntDoubleType);

}

return IntDoubleType;
}

int main (int argc, char** argv) {
int rank, size, value_int, i;
double value_double;
IntDouble value;
MPI_Status status;

MPI_Init (&argc, &argv); /* starts MPI */
MPI_Comm_rank (MPI_COMM_WORLD, &rank); /* get current process id */
MPI_Comm_size (MPI_COMM_WORLD, &size); /* get number of processes */
create_int_double_type();
printf("process %d of %d\n", rank, size);

do {
if(rank == 0) {
printf("give me an int value: ");
scanf("%d", &value_int);
printf("give me a double value: ");
scanf("%lf", &value_double);
value.value_int = value_int;
value.value_double = value_double;
MPI_Bcast(&value, 1, IntDoubleType, 0, MPI_COMM_WORLD);
}
else {
MPI_Recv(&value, 1, IntDoubleType, 0, 1, MPI_COMM_WORLD, &status);
printf("process %d received %d %lf\n", rank, value.value_int,
value.value_double);
fflush(stdout);
}
} while(value.value_int >= 0);
printf("negative value, closing\n");

MPI_Finalize();
return 0;
}



aca la resolucion en erlang:

-module(ej3).
-export([run/1]).

run(Total) ->
Pids = spawn_listeners(Total),
get_values(Pids).

spawn_listeners(Count) -> spawn_listeners(Count, []).

spawn_listeners(0, Pids) -> Pids;
spawn_listeners(Count, Pids) ->
Pid = spawn(fun() -> listener() end),
spawn_listeners(Count - 1, [Pid|Pids]).

listener() ->
receive
{Int, Double} ->
io:format("process ~p received ~p ~p~n", [self(), Int, Double]),
if
Int >= 0 -> listener();
true ->
io:format("negative value, closing ~p~n", [self()])
end
end.

get_value(Message, ConversionFun) ->
case io:get_line(Message) of
{error, Reason} -> {error, Reason};
eof -> {error, eof};
Value -> ConversionFun(Value)
end.

get_values(Pids) ->
case get_value("give me an int value (negative to quit): ", fun(Val) -> string:to_integer(Val) end) of
{error, Reason} ->
io:format("error reading int value (~p)~n", [Reason]),
get_values(Pids);
{IntValue, _Rest} ->
case get_value("give me a double value): ", fun(Val) -> string:to_float(Val) end) of
{error, Reason} ->
io:format("error reading double value (~p)~n", [Reason]),
get_values(Pids);
{DoubleValue, _Rest} ->
send_values({IntValue, DoubleValue}, Pids),
if
IntValue >= 0 -> get_values(Pids);
true -> io:format("negative value, closing~n")
end
end
end.

send_values(Value, Pids) ->
lists:foreach(fun(Pid) -> Pid ! Value end, Pids).



Algunas observaciones.
Cuando el problema empieza a escalar en complejidad de los tipos de datos enviados vemos que erlang empieza a hacernos las tareas mas faciles sin tener que declarar tipos complejos antes de enviarlos.
Otra cosa que note es que erlang un poco nos obliga a tratar los errores con el tema de pattern matching por lo que si bien el codigo erlang es un poco mas largo en realidad esta teniendo en cuenta todos los posibles casos de fallo, en el de C por ejemplo si no entro un entero o un float, el comportamiento es indeterminado (en mi maquina se mete en un loop infinito haciendo printf). Ya se que deberia usar algo como un buffer de string y despues usar atoi o similar pero para algo esta scanf :D.

Resolviendo ejercicios de MPI (y tambien en erlang) Parte 2

enunciado del ejercicio 2

Write a program that reads an integer value from the terminal and distributes the value to all of the MPI processes. Each process should print out its rank and the value it received. Values should be read until a negative integer is given as input.

lo resolvi ahi nomas con MPI, lo corri y todo andaba bien excepto que los procesos no imprimian (excepto el rank 0), pelee, toque, agregue fflush(stdout) y printf's por todos lados (clasica estrategia de debugger artesanal de C :D) y nada, copie el ejercicio resuelto de la pagina y le pasa lo mismo, asi que asumo que es algo relacionado con que mi notebook no es un cluster y encima tiene un solo core. aunque no sirva de mucho, aca esta la resolucion en C:

#include <stdio.h>
#include <mpi.h>

int main (int argc, char** argv) {
int rank, size, value, i;
MPI_Status status;

MPI_Init (&argc, &argv); /* starts MPI */
MPI_Comm_rank (MPI_COMM_WORLD, &rank); /* get current process id */
MPI_Comm_size (MPI_COMM_WORLD, &size); /* get number of processes */
printf("process %d of %d\n", rank, size);

do {
if(rank == 0) {
printf("give me a value: ");
scanf("%d", &value);
MPI_Bcast(&value, 1, MPI_INT, 0, MPI_COMM_WORLD);
}
else {
MPI_Recv(&value, 1, MPI_INT, 0, 1, MPI_COMM_WORLD, &status);
printf("process %d received %d\n", rank, value);
fflush(stdout);
}
} while(value >= 0);
printf("negative value, closing\n");

MPI_Finalize();
return 0;
}


el programa compila y corre, por el hecho de que me pida los valores sucesivos asumo que los procesos estan recibiendo los valores (si no se colgaria en el broadcast) pero de todas formas no imprime.

bueno, pase a la resolucion en erlang, aca esta el codigo:

-module(ej2).
-export([run/1]).

run(Total) ->
Pids = spawn_listeners(Total),
get_values(Pids).

spawn_listeners(Count) -> spawn_listeners(Count, []).

spawn_listeners(0, Pids) -> Pids;
spawn_listeners(Count, Pids) ->
Pid = spawn(fun() -> listener() end),
spawn_listeners(Count - 1, [Pid|Pids]).

listener() ->
receive
Number ->
io:format("process ~p received ~p~n", [self(), Number]),
if
Number >= 0 -> listener();
true ->
io:format("negative value, closing ~p~n", [self()])
end
end.

get_values(Pids) ->
case io:get_line("give me a value (negative to quit): ") of
{error, Reason} ->
io:format("error reading value (~p)~n", [Reason]);
eof ->
io:format("error reading value~n");
Value ->
case string:to_integer(Value) of
{error, Reason} ->
io:format("invalid value (~p)~n", [Reason]),
get_values(Pids);
{IntValue, _Rest} ->
send_values(IntValue, Pids),
if
IntValue >= 0 -> get_values(Pids);
true -> io:format("negative value, closing~n")
end
end
end.

send_values(Value, Pids) ->
lists:foreach(fun(Pid) -> Pid ! Value end, Pids).



algunas observaciones, en este programa se pueden crear multiples grupos que escuchen a multiples entradas y de tamaños variables sin cambiar el codigo.
Una observacion sobre erlang es lo raro que es la convencion de los delimitadores, por ejemplo:

  • Si es la ultima sentencia de una funcion va con punto (a excepcion de que este haciendo pattern matching en cuyo caso todos menos la ultima son con punto y coma)
  • Si es una sentencia comun dentro de una funcion termina en coma, a excepcion de que sea la ultima de la funcion (en cuyo caso punto o punto y coma como vimos arriba) pero tambien a excepcion de que sea la ultima de un if, case, receive en cuyo caso es ;, pero no si es la ultima del ultimo statement en cuyo caso no lleva nada.
estas son algunas nomas, no me costo mucho entenderlas pero lleva un tiempo acostumbrarse y por ahi le erras, mas si moves codigo o agregas statements en cuyo caso tenes que revisar los terminadores.

ejemplo de la salida del de erlang (probando enteros positivos, negativos y valores invalidos):



$ erl
Erlang (BEAM) emulator version 5.6.5 [source] [async-threads:0] [kernel-poll:false]

Eshell V5.6.5 (abort with ^G)
1> c(ej2).
{ok,ej2}
2> ej2:run(4).
give me a value (negative to quit): 42
process <0.41.0> received 42
process <0.40.0> received 42
process <0.39.0> received 42
process <0.38.0> received 42
give me a value (negative to quit): 7
process <0.41.0> received 7
process <0.40.0> received 7
process <0.39.0> received 7
process <0.38.0> received 7
give me a value (negative to quit): -1
negative value, closing
process <0.41.0> received -1
process <0.40.0> received -1
process <0.39.0> received -1
process <0.38.0> received -1
negative value, closing <0.41.0>
negative value, closing <0.40.0>
negative value, closing <0.39.0>
negative value, closing <0.38.0>
ok
3> ej2:run(4).
give me a value (negative to quit): asd
invalid value (no_integer)
give me a value (negative to quit): -1
negative value, closing
process <0.46.0> received -1
process <0.45.0> received -1
process <0.44.0> received -1
process <0.43.0> received -1
negative value, closing <0.46.0>
negative value, closing <0.45.0>
negative value, closing <0.44.0>
negative value, closing <0.43.0>
ok
4>

Resolviendo ejercicios de MPI(y tambien en erlang)

Como tarea en un grupo de la facultad del que formo parte tenemos que resolver ejercicios de MPI, como yo algo de idea de MPI tengo decidí también resolverlos en erlang para seguir aprendiendo mas de este lenguaje, acá van los enunciados del primer ejercicio y las resoluciones de ambos.

Write a program that uses MPI and has each MPI process print
Hello world from process i of n
using the rank in MPI_COMM_WORLD for i and the size of MPI_COMM_WORLD for n. You can assume that all processes support output for this example.

el ejercicio en C lo pueden ver en el post anterior así que acá pego el de erlang nomas

-module(ej1).
-export([run/1]).

run(Total, Total) -> ok;
run(Count, Total) ->
spawn(fun() -> salute(Total) end),
run(Count + 1, Total).

run(Total) -> run(0, Total).

salute(Total) ->
io:format("Hello world from ~p of ~p~n", [self(), Total]).


como en erlang no hay una forma de saber cuantos procesos totales hay dando vueltas (o al menos no es tan estatico como MPI) decidi pasarle el total y imprimir el PID.

para correrlo y ver la salida la forma facil es:

$ erl ej1.erl
Erlang (BEAM) emulator version 5.6.5 [source] [async-threads:0] [kernel-poll:false]

Eshell V5.6.5 (abort with ^G)
1> c(ej1).
{ok,ej1}
2> ej1:run(4).
Hello world from <0.42.0> of 4
Hello world from <0.43.0> of 4
Hello world from <0.44.0> of 4
Hello world from <0.45.0> of 4
ok
3>

todo en orden, vamos a por el segundo

como nota al margen, donde hice el pattern matching de

run(Total, Total) -> ok;

podria haber hecho

run(0, _Total) -> ok;

y contar al reves en

run(Count + 1, Total).

por

run(Count - 1, Total).

pero me parecio mas simpatico contar para adelante :P

sábado, julio 18, 2009

mpi en ubuntu

como instalar y usar mpi en ubuntu para programar?

sudo aptitude install mpich-bin libmpich1.0-dev ssh

iniciamos el servidor ssh:

sudo /etc/init.d/ssh start

creamos un archivo hello.c


/* C Example */
#include <stdio.h>
#include <mpi.h>

int main (int argc, char** argv)
{
int rank, size;

MPI_Init (&argc, &argv); /* starts MPI */
MPI_Comm_rank (MPI_COMM_WORLD, &rank); /* get current process id */
MPI_Comm_size (MPI_COMM_WORLD, &size); /* get number of processes */
printf( "Hello world from process %d of %d\n", rank, size );
MPI_Finalize();
return 0;
}


compilamos el ejemplo:

mpicc hello.c -o hellompi

corremos el ejemplo con 4 procesos:

mpirun -np 4 ./hellompi

para que no nos pida el password por cada proceso hacemos lo siguiente

generamos las claves para el ssh

ssh-keygen -t dsa

y agregamos la clave a la lista autorizada (si ya tenes ~/.ssh/authorized_keys agrega la clave al final)

cp ~/.ssh/id_dsa.pub ~/.ssh/authorized_keys

y volia!

mariano@ganesha:~$ mpirun -np 4 ./hellompi
Hello world from process 0 of 4
Hello world from process 2 of 4
Hello world from process 1 of 4
Hello world from process 3 of 4

PD: yo ya tenia instalado build-essential, si no lo instala hay que instalarlo a mano
PD2: esto funciona en debian y derivados, en fedora supongo que hay que cambiar aptitude por yum y sale andando

sábado, julio 11, 2009

Frase interesante

hoy leí esta frase:

Typesafe languages eliminate these problems by design. Instead of just exhorting programmers to be more careful, typesafe languages put mechanisms in place which guarantee that they cannot happen.

y mi cerebro pensó que esta buena la frase para aplicarla mas genéricamente:

Thing X eliminate these problems by design. Instead of just exhorting Users to be more careful, Thing X put mechanisms in place which guarantee that they cannot happen.

esto me paso después de leer sobre NewSqueak y Limbo en los cuales algunos problemas de la programacion concurrente no existen por cuestion de diseño. Pase a pensar en como se puede diseñar algo para que los problemas no puedan suceder.

lunes, julio 06, 2009

quotequotequote

soy adicto a los quotes :)

The cheapest, fastest, and most reliable components are those that aren't there.

-- Gordon Bell

One of my most productive days was throwing away 1000 lines of code.

-- Ken Thompson

Deleted code is debugged code.

-- Jeff Sickel

The most effective debugging tool is still careful thought, coupled with judiciously placed print statements.

-- Brian W. Kernighan, in the paper Unix for Beginners (1979)

Beauty is more important in computing than anywhere else in technology because software is so complicated. Beauty is the ultimate defence against complexity.

-- David Gelernter

UNIX was not designed to stop its users from doing stupid things, as that would also stop them from doing clever things.

-- Doug Gwyn

If you're willing to restrict the flexibility of your approach, you can almost always do something better.

-- John Carmack

All software sucks, be it open-source [or] proprietary. The only question is what can be done with particular instance of suckage, and that's where having the source matters.

-- viro [http://www.ussg.iu.edu/hypermail/linux/kernel/0404.3/1344.html]

It's not that perl programmers are idiots, it's that the language rewards idiotic behavior in a way that no other language or tool has ever done.

-- Erik Naggum, comp.lang.lisp

Simplicity is prerequisite for reliability.

-- Edsger W. Dijkstra

Beware of "the real world". A speaker's apeal to it is always an invitation not to challenge his tacit assumptions.

-- Edsger W. Dijkstra

Unix is a junk OS designed by a committee of PhDs

-- Dave Cutler

Forward thinking was just the thing that made multics what it is today.

-- Erik Quanstrom

I remarked to Dennis [Ritchie] that easily half the code I was writing in Multics was error recovery code. He said, "We left all that stuff out [of Unix]. If there's an error, we have this routine called panic, and when it is called, the machine crashes, and you holler down the hall, 'Hey, reboot it.'"

-- Tom Van Vleck [http://www.multicians.org/unix.html]

The key to performance is elegance, not battalions of special cases.

-- Jon Bentley and Doug McIlroy

Measuring programming progress by lines of code is like measuring aircraft building progress by weight.

   -- Bill Gates

Haskell is faster than C++, more concise than Perl, more regular than Python, more flexible than Ruby, more typeful than C#, more robust than Java, and has absolutely nothing in common with PHP.

-- Autrijus Tang

Object-oriented design is the roman numerals of computing.

-- Rob Pike

{ajh} I always viewed HURD development like the Special Olympics of free software.


We have persistant(sic) objects, they're called files.

-- Ken Thompson

Simplicity is the ultimate sophistication.

   -- Leonardo da Vinci

Increasingly, people seem to misinterpret complexity as sophistication, which is baffling---the incomprehensible should cause suspicion rather than admiration. Possibly this trend results from a mistaken belief that using a somewhat mysterious device confers an aura of power on the user.

-- Niklaus Wirth

y como cierre para divertirse un buen rato:

http://harmful.cat-v.org/software/java
http://harmful.cat-v.org/software/c++/

Seguidores

Archivo del Blog