Una visión general de RMI

“Esto es una traduccion on the fly de http://java.sun.com/docs/books/tutorial/rmi/overview.html”

RMI (Java Remote Method Invocatión) es la tecnología que nos ofrece Java para ejecutar metodos en una maquina virtual remota.

Supongamos que tenemos nuestro programa ejecutándose en nuestro PC Local (Un pentium II 350) y necesitamos realizar llamar a un método que ejecuta un abultado numero de threads para calcular algo y en la oficina es todo maquinaria antigua excepto un UltraSPARC T1  que nos reduce el tiempo de espera en unos cuantos minutos.

En un escenario como el descrito anteriormente RMI se perfila como una alternativa a tener en cuenta.

Las aplicaciones que utilicen objetos remotos necesitan realizar las siguientes acciones:

  • Localizar Objetos Remotos Las aplicaciones pueden utilizar diversos mecanismos para obtener referencias de objetos remotos. Por ejemplo: Una aplicación puede registrar sus objetos remotos con las características del registro de RMI o de forma alternativa una aplicacion puede trabajar con referencias de objetos distribuidos en sus metodos locales.
  • Comunicarse con Objetos Remotos Los detalles de la comunicación entre objetos remotos son gestionadas por RMI, para el programador la comunicación remota actuá como las llamadas clásicas a métodos.
  • Cargar las definiciones de las clases para los objetos que recibe RMI permite que los objetos sean devueltos, por eso incluye mecanismos para cargar definiciones de objetos y transmitir los datos de los mismos.

La siguiente ilustración describe una aplicación distribuida que usa el registro RMI para obtener una referencia a un objeto remoto. El servidor llama al registro para asociar un nombre con un objeto remoto. El cliente busca el objeto remoto en el registro del servidor y despues llama a un metodo del objeto. La ilustración también muestra como RMI utiliza un servidor web existente para obtener las definiciones de las clases. en la comunicación cliente-servidor y viceversa cuando es necesario

esquema RMI

Ventajas de la carga dinámica de código

Una de las características centrales y únicas de RMI es la capacidad de descargar la definición de un objeto si la clase no esta definida en la maquina virtual del receptor. Todo los tipos y comportamientos de un objeto, anteriormente disponibles en una única maquina virtual, pueden ser transmitidos a otra maquina virtual. RMI transporta objetos con sus clases, el comportamiento de sus objetos no cambia cuando es enviada a otra maquina virtual, de esta manera amplia el comportamiento de la aplicación.

Interfaces remotas, objetos y metodos

Como cualquier otra aplicacion en Java una aplicacion distribuida esta compuesta de interfaces y clases. Una interfaz declara metodos, las clases implementan los metodos declarados por la interfaz y puede contener metodos adicionales. En una aplicacion distribuida algunas implementaciones pueden residir en algunas maquinas virtuales pero no en otras. Objetos con metodos que pueden ser invocados entre maquinas virtuales se llaman objetos remotos.

Un objeto se tranforma en remoto implementando la interfaz remote, que tiene las siguientes caracteristicas:

  • Una interfaz remota extiende la interz java.rmi.Remote.
  • Cada método de la interfaz declara java.rmi.RemoteException en su clausulas throws, en adicción a cualquier excepción especifica de la aplicación.

RMI trata un objeto remoto de una forma diferente a un objeto no remoto cuando el objeto es pasado entre maquinas virtuales. mas que hacer una copia de la implementacion del objeto en la maquina virtual receptora, RMI pasa un stub remoto para un objeto remoto. El stub actua como la representacion local, o proxe, para el objeto remoto y para el cliente como una referencia remota. El cliente invoca al metodo desde el stub local el cual es el reponsable de transportar la invocarcion al metodo en el objeto remoto.

Un stub para un objeto remoto implementa el mismo conjuto de interfaces remotas que el objeto remoto. Esto permite que el stub pueda ser modelado (casting) a cualquiera de las interfaces que el objeto remoto implementas. De todas formas, solo los metods definidos en la interfaz remota estan disponibles para ser invocados el la maquina virtual receptora.

Creando Aplicaciones distrribuidas usando RMI

Utilizar RMI para desarrolar una aplicacion distribuida nos obliga a incluir estos pasos generales

  • Diseñar e implementar los componentes de tu aplicación distribuida
  • Compilar los fuentes
  • Hacer las clases accesibles desde la red
  • iniciar la aplicación

Diseñar e implementar los componentes de tu aplicacion distribuida

Primeramente determina la arquitectura de tu aplicación, incluyendo que componentes son objetos locales y que componentes son acesibles de forma remota. Este paso incluye:

  • Definir las interfaces remotas. Una interfaz remota especifica que métodos puede ser invocados por el cliente. Los programas clientes usan esas interfaces remotas y no la implementación de esas interfaces. El diseño de las interfaces incluye la definicion de los tipos de objetos que seran usados como parametros y valores de retorno para esos metodos. Si alguna de esas intarfaces o clases aun no existe tu deberas definirlas.
  • Implementar los objetos remotos. Los bjetos remotos deben implementar una o mas interfaces romatas. La clase del objeto remoto debe incluir las implementaciones de las otras interfaces y metodos que esten disponibles solo de forma local. Si alguna clase local es usada para parametros o valores de retorno estas deben ser implementadas tambien.
  • Implementar los clientes. Los clientes que usan los objetos remotos pueden ser implimentadas en cualquier momentos despues de que las interfaces remotas esten definidas, incluso despues que los objetos remotos hayan sido desarrollados.

Compilar los Fuentes

Como en cualquier programa en Java, tu debes usar el compilador javac para compilar los fuentes, el codigo fuente contiene las declaraciones de las interfaces remotas, sus implementaciones, cualquier otra clase del servidor y los clases del cliente.

nota: Las versiones ateriores a la Hava Standard Edition 5.0, como paso adicional requieren la creacion de los stub usando rmic

Haciendo las Clases accesibles por la Red

En este paso tu haras que ciertas definiciones de clases sean accesibles en la red, como la definicion de interfaces remotas y sus tipos asocidaos, y la definicion para las clases que necesitan ser descargadas para los clientes o servidores. Las difiniciones de clases generalmente se hacen accesibles a traves de un servidor web.

Construyendo un Motor de computo generico

Nos centraremos en una simple, pero poderosa, aplicación distribuida llamada motor de computo. El motor decomputo es un objeto remoto en el servidor que toma tareas de los clientes, ejecuta las tareas y retorna los resultados. Las tareas estan corriendo en la misma maquina que el servidar. Este tipo de aplicaciones distribuidas puede activar un numero de maquinas cliente para hacer uso de una maquina particularmente potente o con hardware especializado.

Los aspectos noveles del motor de computo son que las tareas que ejecuta no necesitan ser definidas cuando el motor de computo esta escrito o iniciado. Nuevos tipos de tareas pueden ser creados en cualquier momento y después enviadas al motor de computo. El único requerimiento de las tareas es que sus clases implemente una interfaz en particular. El código necesario para cumplir la tarea puede ser descargado por el sistema RMI al motor de computo. Entonces, el motor de computo ejecuta la tarea usando los recursos de la maquina donde ser esta ejecutado dicho motor.

La capacidad para realizar tareas arbitrarias esta disponible por la naturaleza dinámica de la plataforma java, que es extendida a traver de la red gracias a RMI. RMI caga de forma dinámica el código de la tarea en el motor de computo de la maquina virtual de java y ejecuta la tarea sin conocimiento previo de la implementacion de la tarea. Como las aplicaciones  con la capacidad de descargar el codigo de forma dinamica, tambien llamadas aplicaciones basadas en comportamientos, estas aplicaciones requeres una infraestructura de agentes activos. Com RMI estas aplicaciones son parte del mecanismo basica para computacion distribuida de la plataforma java.

Escribiendo un servidor RMI

El servidor del motor de computo acceta tareas de los clientes, ejecuta la tarea y devuelve los resultados, el codigo del servidor consuste en una interfaz y una clases. La interfaz define los metodos que pueden ser invocados por el clientes. Esencialmente lainterfaz define la vista de los objetos remotos para los clientes, la clases nos provee de las implementaciones.

Diseñando Una Interfaz remota

El corazon del motor de computacion es un protocolo que permite que las tareas sean enviadas al mismo, el motor de computo ejecuta esas tareas y el resultado de la ejecución es enviado al cliente. Este protocolo esta introducido en las interfaces que son soportadas por el motor de computo.

Comunicación RMI

Cada interfaz contiene un único método. La interfaz remota del motor de computo, Compute, permite a las tareas ser enviadas al motor. La interfaz cliente, Task, define como el motor de computo ejecuta una tarea enviada.

La interfaz compute.Compute define la parte accesible de forma remota, el motor de computo en si mismo, Aqui pongo el codigo de la interfaz Compute:

package compute;

import java.rmi.Remote;
import java.rmi.RemoteException;

public interface Compute extends Remote {
<T> T executeTask(Task<T> t) throws RemoteException;
}

Al extender la interfaz java.rmi.Remote, la interfaz compute se identifica como una interfaz cuyos métodos pueden ser invocados desde otra maquina virtual. Cualquier objeto que implementa esta interfaz puede ser un objeto remoto.

Como miembro de una interfaz remota, el método executeTask es un método remoto. De todas formas este método debe ser definido para ser capar de ignorar una java.rmi.RemoteException. Esta excepción es ignorada por el sistema RMI en la invocación de métodos remotos para indicar fallos de comunicación o errores del protocola. Una RemoteExcepcion es una excepción comprobada, pero cualquier código que invoque a un método remoto necesita manejar esta excepción con un catch o con una cláusula throws.

La segunda interfaz necesaria para el motor de computo es la interfaz Task, que es el tipo de parametro del metodo executeTask en la interfaz compute. Aqui teneis es codigo de la interfaz Task

package compute;

public interface Task<T> {
T execute();
}

La interfaz task define un único método, execute, que no tiene parámetros ni ignora ninguna excepción. Porque la interfaz no extiende a Remote y el método de esta interfaz no necesita ignoros la excepción java.rmi.RemoteException en su cláusula throws.

La interfaz Task tiene un tipo de parámetro T, que representa el tipo de resultado de las tareas a computar. Esta interfaz ejecuta métodos que devuelven el resultado del computo.

RMI usa los mecanismos de serializacion de objetos para transportar los objetos por valor entre maquinas virtuales, Para que un objeto pueda ser serializables, su definición debe implementar la interfaz java.io.Serializable. Por lo tanto las clases que implementen la inteaz Task tambien deben implementar la interfaz Serializable.

Los diferentes tipos de tareas que pueden ser ejecutadas por el Objeto Compute son implemntaciones del tipo Task. Las clases que son implementads por esta interfaz pueden contener cualquier informacion necesitada para la ejecucion de la tarea y cualquier otro metod necesario para la ejecución.

Esta es la forma por la cual RMI hace que este simple motor de computo posible. RMI asume que los objetos Task estan escritos en Java, las implementaciones de los objetos Task que eran desconocidos para el motor de computo son obtenidas por RMI baja demanda, esta capacidad permite a los clientes del motor de computo definir nuevos tipor de tareas para ejecutar en el servidor sin la necesidad de especificar nada en el codigo de la parte del servidor.

El motor de computo implementado por la clase ComputeEngine iplementa la interfaz Compute, permitiendo que distintas tareas sean enviadas a el cn llamadas al metodo executeTask. estas tareas se ejecutan usado de implementacion de Task del metodo execute y los resultados son enviados al cliente remoto.

Implementando una interfaz Remota

Una clase que implementa una intergaz emoto necesida hacer lo siguiente:

  • Declarar las interfaces remotas que implementara
  • Definir los constructores para cada objeto remoto
  • Implementar cada metodo remoto de las interfaces remotas

Un servidor RMI necesita crear los objetos remotos iniciales y exportarlos al entrono de ejecución RMI, lo que les permite al servidor recibir invocaciones remotas. Este paradigma de funcionamiento puede ser encapsulado en un metodo de la implementación del objeto remoto o ser incluida en otra clase. El paradigma de funcionamiento debe realizar la siguientes acciones:

  • Crear e instalar un gestor de seguridad
  • Crear y exportar uno o mas objetos remotos
  • Registrar al menos un objeto remoto con el registro RMI (o con otro servicio de nombe, como un sercio accesible a traves la interfaz Java Namin and Directory) como metodo de arranque.

A continuacion ponemos la implementacion del motor de computo. La clase engine.ComputeEngine implementa la interfaz remota Computo y tambien incluye el metodo main para iniciar el motor de computo. Aqui teneis el codigo fuentepara la clase ComputeEngine:

package engine;

import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
import compute.Compute;
import compute.Task;

public class ComputeEngine implements Compute {

    public ComputeEngine() {
        super();
    }

    public <T> T executeTask(Task<T> t) {
        return t.execute();
    }

    public static void main(String[] args) {
        if (System.getSecurityManager() == null) {
            System.setSecurityManager(new SecurityManager());
        }
        try {
            String name = "Compute";
            Compute engine = new ComputeEngine();
            Compute stub = (Compute) UnicastRemoteObject.exportObject(engine, 0);
            Registry registry = LocateRegistry.getRegistry();
            registry.rebind(name, stub);
            System.out.println("ComputeEngine bound");
        } catch (Exception e) {
            System.err.println("ComputeEngine exception:");
            e.printStackTrace();
        }
    }
}

A continuación explicaremos cada elemento de la implementacion del motor de computo.

Declarando las interfaces remotas que serán implementadas.

La implementacion del motor de computo es declarada:

public class ComputeEngine implements Compute

Esta declaracion indica que implementamos la interfaz remota Computo y que pude ser usada par los objetos remotos.

La clase ComputeEngine define una implementacion de la clase del objeto remoto que implementa una unica interfaz remota. La clase ComputeEngine tambien contiene dos elementos executables que solo pueden ser invocados de forma local. El primero de esos elementos es el contructor para las instancias de ComputeEngine. El segundo es el metodo main que se usa para clerar la instacion de ComputeEngine que  hace que este disponible para los clientes.

Definiendo el constructor para un objeto remoto.

La clase ComputeEngine tiene un unico contructor que no toma ningun argumento. El codigo del constructor esta a continuación:

public ComputeEngine() {
    super();
}

Este constructor solo invoca al constructor de la superclase, el cual es un constructor sin argumentos de la clase Object. De todas formas el constructor de la superclase es invocado si fuera omitido por el constructor ComputeEngine, esto esta incluido para facilitar la comprension del codigo.

Creando las implementaciones para cada método remoto.

La clase para un objeto remoto implementa cada metodo remoto de la interfaz remota. La interfaz Compute contiene un unico metodo, executeTask, implementacion de la cual se muestra  a continuación

public <T> T executeTask(Task<T> t) {
    return t.execute();
}

Este metodo implementa el protocolo entre el objeto remoto ComputeEngine y sus clientes, ComputeEngine recibe de cada cliente un objeto Task con su implementacion para la interfaz Task y su metodo de ejecución. El ComputeEngine ejecuta cada tarea del cliento y devielve lo resultados de la ejecucion al cliente.

Pasando Objetos en RMI

Los argumentos o valores de retorno de los métodos remotos pueden ser de cualquier tipo, incluyendo objetos locales, objetos remotos y tipos de datos primitivos. De forma mas preciso cualquier entidad de cualquier tipo puede ser pasada o recibida desde un objeto remoto, un objero remoto, o un objeto serializable (lo que significa que implementa la interfaz java.io.Serializable).

Algunos tipos de objeto no cumple alguno de estos criterios y por lo tanto no pueden ser pasados o recibidos por un método remoto, Muchos de esos objetos, como threads o descriptos de archivos, encapsulan información que solo tiene sentido en un único espacio de memorio, Muchas de las clases del núcleo de java incluyendo las clases en los paquetes java.lang y java.util implementan la interface Serializable.

Las reglas que rigen las condiciones para que los argumentos o valores de retorno sean validos son las siguientes:
*Los objetos remotos se pasa esencialmente por referencia. Una referencia a un objeto remote es un stub, que es un proxy del lado del cliente que implementa el conjunto completo de interfaces que implementa un objeto remoto.
*Los objetos locales son pasados como una copia, usando serializacion de objetos. Por defecto , todos los campos son copiados excepto los que están marcados como static o transient, El comportamiento predeterminado de la serializacion pude ser sobrescrito.

Pasar un objeto remoto por referencia significa que cualquier cambio realizado en el estado del objeto por la invocación remota queda reflejado en lo objeto remoto original. Cuando un objeto remoto es pasado, solo las interfaces que son interfaces remotas están disponibles para el receptor. Cualquier motoso definido en la implementación de la clase o definido en las interfaces no remotas implementadas por la clase no estan disponibles para el receptor.

Por ejemplo, if estuvieramos pasando una referencia a una instancia de la clase ComputeEngine, el receptor solo tendria acceso al metodo executeTask. El receptor no veria el constructor de ComputeEngine, su metodo main o sun implementaciones de cualquier metodo de java.lang.Object.

En los parámetros y valores de retorno de las invocaciones remotas a metodos, los objetos que no son objetos remotos son pasados por valor, osea , una copia del objeto es creada en la maquina virtual receptora. Cualquier cambio en el estado del objeto por el receptor se ve reflejado unacamente en la copia del receptor, no en la instancia original enviada. Cualquier cambio en el estado del objeto realizado por el enviador se ve reflejado solo en la instancia original del envio, no en la copia del receptor.

Implementando el metodo main del Servidor

El metodo mas complejo de la implementacion de ComputeEngine es el metodo main. El metodo main es usado para iniciar el motor de computo y necesita realizar la inicializacion para preparar el servidor para aceptar llamadas de los clientes. Este metodo no es un metodo remoto, lo que significa que no puede ser invocado por una maquina virtual diferente. A causa que que el metodo main esta declarado como static, el metodo no esta asociado con el objeto o mejor dicho con la clase ComputeEngine.

Creando e instalando un gestor de seguridad

La primera tarea del metodo main es crear e instalar un gestor de seguridad (Security Manager), ue protege el aceso a los recursos del sistema de codigo no verificado que transcurre entre maquinas virtuales. Un gestor de seguridad determina que codigo descargado tiene acceso al sistema de archivos locales o puede realizar cualquier otra operación privilegiada.

Si un programa RMI no instala un gestor de seguridad, RMI no descargara clases (que no esten en su class path) para los objetos recibidos como argumentos o valores de retorno de los metodos remotos. Esta restricción nos asegura que las operaciones realizadas con condigo descargado estan sujetas a una politica de seguridad.

Aqui esta el codigo que crea e instala un gestor de seguridad:

if (System.getSecurityManager() == null) {
 System.setSecurityManager(new SecurityManager());
}

Haciendo los objetos remotos disponibles para los clientes

El metodo main clea una instancia de ComputeEngine y lo exporta para el entono de ejecucion de RMI con las sigioentes lineas


Compute engine = new ComputeEngine();
Compute stub =

(Compute) UnicastRemoteObject.exportObject(engine, 0);

El metodo estatico UnicastRemoteObject.exportObject exporta el objeto remodo pasado como parametro para que pueda recibir invocaciones de sus metodos remotos a traves de clientes remotos. El segundo argumento, un int, especifica que puerto TCP sera usado para escuchar solicitudes para las invocaciones remotas. Generalmente el valor es cero, que especifica el uso de un puerto anónimo. El puerto actual sera seleccionado por RMI en tiempo de ejecución o por el sistema operativo. De todas formas un valor distinto a  cero puede ser usado para especificar el puerto de escucha. Una vez que la invocación  a exportObject se ha realizado de forma satisfactoria, el objeto remoto ComputeEngine esta listo para recibir invocaciones remotas.

El metodo exportObject devuelve un stub del objeto remoto esportado. Fijate que el tipo de variable stub debe ser Compute, no ComputeEngine, porque el stub de un objeto remoto solo implementa las interfaces remotasde los objetos remotos exportados implementados.

El exportObject motodo declara que puede ignorar una RemoteException, que es un tipo de excepcion comprobada. El metodo main maneja esta exception con sus bloques try/catch. Si la excepcion no esta manejada de esta manera el metodo main debera ignorar (throws) la RemoteException si lo recursos necesarios no estan disponibles, como que el puerto este ocupado para otros objetivos.

Antes de que el cliente pueda invocar un metodo de un objeto remoto, primero se debe obtener una referencia al objeto remoto.  Para obtener esta referencian se puede hacer de la misma forma por la que cualquier referenca a un objeto es obtenida por el programa, como obtener l referencia como parte de un valor de retorno o como parte de una estructura de datos que contiene dicha referencia.

El sistema nos provee de un tipo de objeto remoto particular, el registro RMI, para encontrar referencias a otros objetos remotos. El registro RMI es un servicio de nombres de objeto que permite a los clientes obtener una referencia a un objeto remoto por su nombre. El registro es usado generalmente para encontrar el primer objeto remoto que el cliente RMI necesita usar. Ese primer objeto puede ser usado para encontrar otros objetos.

La interfaz java.rmi.registry.Registry es el API para registrar y buscar objetos remotos en el registro. La clase java.rmi.registry.LocateRegistry contiene metodos estaticos para sintetizar una referencia remota a un registro en una direccion de red particular (host y puerto). Estos metodos crean la referencia remota a un objeto que contiene la direccion de red pero sin realizar ninguna comunicacion remota. LacaleRegistry tambien contiene metodos estaticos para crear un nuevo registro en la maquina virtual actual, de todas formas este ejemplo no usa esos metodos. Una vez que el objeto remoto esta registrado en el registro RMI del host local, los clientes de cualquier host puede bscar el objeto remoto por su nombre, obteniendo ss referencias y luego invocar los metodos remotos del objeto. El registro puede ser compartido por todos los servidores de un host, o un unico proceso servidor puede crear su propio registro.

La clase ComputeEngine crea un nombre para el objeto con la siguiente linea:

String name = "Compute";

Este codigo añade el nombre al registro RMI del servidor. Este para se reliza antes de los siguientes comando

Registry registry = LocateRegistry.getRegistry();
registry.rebind(name, stub);

La llamada a rebind realiza una llamada al registro RMI del host local. Como cualquier llamada remota, esta puede generar una RemoteExceptionque sera manejada en bloque catch del metodo main.

Ten en cuenta las siguientes condiciones el las llamadas a Registry.rebind:

  • La sobrecarga sin argumentos a LocateRegistry.getRegistry sintetiza una referencia a iun registroen el host local y en su puerto predeterminado,1099. Tu debes usar una sobrecarga que tiene un parametro int si el registro esta creado en un puerdo distinto al 1099.
  • Cuando se realia una invocacion al registro, se pasa un stub del objeto remoto en lugar de una copia del objeto remoto. Las implementaciones de objetos remotos, como las instancias de ComputeEngine, nunca abandonaran la maquina virtual donde fueron creadas. Asi que, cuando un cliente realiza una busqueda en un servidor de registro de objetos remotos, una copia del stub (boceto) es devuelta. Los objetos remotos generalente son mas efecientes pasados como una referencia remota en lugar que por valor
  • Por razones de seguridad, una aplicacion solo puede realizar operaciones bind, unbind o rebind con referencias a objetos con un registro ejecutandosse en el mismo host. Esta restriccion nos ayuda a evitar que un cliente remoto borre o sobreescriba alguna estrada del servidor de registro. De todas formas una lookup (busqueda), puede ser solicitada por cualquier host, local o remoto.

Una vez que el servidor ha sido registrado con el registro local RMI, muestra un mensaje indicando que esta listo para empezar a manejar llamadas. Entonces, el metodo main se completa. No es necesario usar threads para mantener el servidor manejando escuchas.Mientras exista referencia al objeto ComputeEngine en otra maquina virtual, local o remota, el objeto ComputeEngine no se destruirá ni le afectara el recolector de basura, Porque el programa maneja una referencia a ComputeEngine que esta en el registro, que es accesible por el cliente remoto. El sistema RMI mantiene mantiene los procesos ComputeEngine ejecutandose. El ComputeEngine esta disponible para aceptar llamadas y no será utilizado hasque que su enlace sea eliminado por el registro y los clientes no remotos rompan la referencia remota al objeto CompteEngine.

La ultima porción de código en el método  ComputeEngine.main manejo cualquier posible excepción. El único tipo de excepción comprobada que puede ser ignorada en el código es la RemoteException, a través la llamada a UnicastRemoteObject.exportObject o por la llamada al método rebind. De cualquier forma, el programa no puede hacer mucho mas que salir después de imprimir un mensaje de error. En algunas aplicaciones distribuidas es posible recuperarse del fallo para realizar llamadas remotas. Por ejemplo, la aplicación podría hacer un reintento o seleccionar otro servidor para continuar funcionando.

Creando un programa Cliente

El motor de computo (compute engine) es un programa relativamente simple. Ejecuta tareas que son manejadas para eso. Los clientes de motor de computo son mas complejos. Un cliente necesita llamar al motor de computo, pero también tiene que definir las tareas que se ejecutarán en el motor de computo.
Dos clases separadas forman el cliente de nuestro ejemplo. La primera clase, ComputePi, busca e invoca un objeto Compute. La segunda clase, Pi, implementa la interfaz Task y define el trabajo para ser realizado por el motor de computo. El trabajo de la clase Pi es computar el valor de algunos decimales de Pi .

La interfaz no remota Task esta definida a continuación:

package compute;

public interface Task<T> {
 T execute();
}

Aquí estas el código fuente para cliente-ComputePi (link) :

<pre>package client;

import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.math.BigDecimal;
import compute.Compute;

public class ComputePi {

 public static void main(String args[]) {
 if (System.getSecurityManager() == null) {
 System.setSecurityManager(new SecurityManager());
 }
 try {
 String name = "Compute";
 Registry registry = LocateRegistry.getRegistry(args[0]);
 Compute comp = (Compute) registry.lookup(name);
 Pi task = new Pi(Integer.parseInt(args[1]));
 BigDecimal pi = comp.executeTask(task);
 System.out.println(pi);
 } catch (Exception e) {
 System.err.println("ComputePi exception:");
 e.printStackTrace();
 }
 }
}

Igual que el servidor ComputeEngine, el cliente comienza instalando un gesto de seguridad. Este paso es necesario porque durante el proceso de recibir los borradores (stub) de los objetos remotos del servidor puede ser necesario descargar las definiciones de clases del servidor. Para que RMI descargue clases el gesto de seguridad debe ser forzado.
Después de instalar el gestor de seguridad, el cliente construye un nombre para realizar las búsquedas de los objetos remotos Compute, usando el mismo nombre que usa ComputeEngine para unirse con el cliente. También el cliente usa la API LocaleRegistry.getRegistry para sintetizar una referencia remota para registras el host remoto. El valor de primer argumento de los argumentos pasados por consola, args[0], es el nombre del host remoto en el que se ejecuta el objeto Compute. Entonces el cliente invoca al método lookup en el registro para buscar el objeto remoto por nombre en el registro del host servidor. La sobrecarga particular de LocateRegistry.getRegistry  que solo tiene un parámetro una String, devuelve una referencia al registro del host remoto en el puerto 1099. Si el puerto del servidor es distinto al 1099 debes usar la sobrecarga que tiene un parámetro int.

A Continuación el cliente crea un nuevo objeto Pi, pasando al constructor de pi el valor del segundo argumento de los argumentos de la linea de comandos, args[1], pasada como un entero. Este argumento indica el numero de valores decimales para ser calculados. Finalmente el cliente invoca al método executeTask recibiendo un objeto del tipo BigDecimal, que el programa almacena en la variable result. El siguiente gráfico describe el flujo entre el cliente ComputePi, el rmiregistry (registro mi) y el ComputeEngine (motor de computo).

Flujo elementos RMI

La clase Pi implementa la interfaz Task y calcula el valor de un numero de decimales de Pi. Para este ejemplo, el algoritmo no es importante. Lo que si es importante del algoritmo es su coste computacional lo que significa que se deberá ejecutar en un servidor capacitado.
Aquí esta el código fuente para el cliente.Pi la clase que implementa la interfaz Task:

</pre>
package client;
import compute.Task;

import java.io.Serializable;

import java.math.BigDecimal;
public class Pi implements Task<BigDecimal>, Serializable {
 private static final long serialVersionUID = 227L;
 /** constants used in pi computation */

private static final BigDecimal FOUR =

BigDecimal.valueOf(4);
 /** rounding mode to use during pi computation */

private static final int roundingMode =

BigDecimal.ROUND_HALF_EVEN;
 /** digits of precision after the decimal point */

private final int digits;
 /**

* Construct a task to calculate pi to the specified

* precision.

*/

public Pi(int digits) {

this.digits = digits;

}
 /**

* Calculate pi.

*/

public BigDecimal execute() {

return computePi(digits);

}
 /**

* Compute the value of pi to the specified number of

* digits after the decimal point.  The value is

* computed using Machin's formula:

*

*          pi/4 = 4*arctan(1/5) - arctan(1/239)

*

* and a power series expansion of arctan(x) to

* sufficient precision.

*/

public static BigDecimal computePi(int digits) {

int scale = digits + 5;

BigDecimal arctan1_5 = arctan(5, scale);

BigDecimal arctan1_239 = arctan(239, scale);

BigDecimal pi = arctan1_5.multiply(FOUR).subtract(

arctan1_239).multiply(FOUR);

return pi.setScale(digits,

BigDecimal.ROUND_HALF_UP);

}

/**

* Compute the value, in radians, of the arctangent of

* the inverse of the supplied integer to the specified

* number of digits after the decimal point.  The value

* is computed using the power series expansion for the

* arc tangent:

*

* arctan(x) = x - (x^3)/3 + (x^5)/5 - (x^7)/7 +

*     (x^9)/9 ...

*/

public static BigDecimal arctan(int inverseX,

int scale)

{

BigDecimal result, numer, term;

BigDecimal invX = BigDecimal.valueOf(inverseX);

BigDecimal invX2 =

BigDecimal.valueOf(inverseX * inverseX);
 numer = BigDecimal.ONE.divide(invX,

scale, roundingMode);
 result = numer;

int i = 1;

do {

numer =

numer.divide(invX2, scale, roundingMode);

int denom = 2 * i + 1;

term =

numer.divide(BigDecimal.valueOf(denom),

scale, roundingMode);

if ((i % 2) != 0) {

result = result.subtract(term);

} else {

result = result.add(term);

}

i++;

} while (term.compareTo(BigDecimal.ZERO) != 0);

return result;

}

}
<pre>

Notese que todas las clases serializables, aquellas que implementan las interfaces serializable directa o indirectamenta, deben declarar un campo private static final llamado seriaVersionUID para garantizar la compativilidad entre versiones. Si no en existe una versión previa de la clase, entonces el valor de este campo puede ser cualquier valor long, similar al de 227L usado por pi, segun la longitud del valor sera usado en versiones futuras. Si existiese una versión previa de la clase si una declaracion explicita de serialVersionUID , pero la compatibilidad con la versión anterior es importante, entonce el valor implícito predeterminado para computar sera el que debera ser usado para el valor de la nueva versión. La herramienta serialver puede determinar el valor predeterminado a usar.

La caracteristica mas importante de este ejemplo es que la implementación del objeto value nunca necesita la definición de la clase Pi hasta que el objeto es pasado como argumento al metodo executeTask. En ese punto, el codigo de la clase es cargado por RMI en la maquina virtual del Objeto Compute, el metodo execute es invocado, y el codigo de la tarea es ejecutado. El resultado, que en el caso de la tarea Pi es un objeto BigDecimal, es retornado al cliente que realizao la llamado, donde es usado para imprimir el resultado del computo.

El hecho de que el objeto Task  compute el valor de Pi es irrelevante para el objeto ComputeEngine. Tu tambien podrias implementar una task que, por ejemplo, generase un numero primo aleatoria. Cualquier tarea podria se intensiva desde el punto de vista computacional  seria una buena candidata para el ComputeEngine, pero requeriria un codigo muy diferente. Este codigo tambien podria ser descargado cuando un objeto Task es pasado a otro Compute. a causa de que el objeto Compute no necesita saber lo que la implementación de Task hace.

proximo post (como poner todo esto en marcha)

Comprobando el rendimiento de los sistemas de archivos de Linux

Uno de los problema mas comunes al instalar Linux o administrar una maquina en Linux es encontrar el sistema de archivos que mas se ajuste a nuestras necesidades. a continuación tenemos un script que creara varios sistemas de archivos y realizara diversas pruebas.

echo "****************************"
echo "*Creating Files for loopback*"
echo "****************************"
echo " "
echo "Creating file"
dd if=/dev/zero of=filesystem.fs count=5000000
echo "Formating btrfs filesystem"
mkfs.btrfs filesystem.fs
mkdir filesystem
echo "Configuring loopback"
losetup /dev/loop0 filesystem.fs
mount -t btrfs /dev/loop0 filesystem
cd filesystem
cp ../script.sh ./
sh script.sh
umount /dev/loop0
echo "Formating ext2 filesystem"
mkfs -t ext2 /dev/loop0
mount -t ext2 /dev/loop0 filesystem
cd filesystem
cp ../script.sh ./
sh script.sh
echo "Formating ext3 filesystem"
mkfs -t ext3 /dev/loop0
mount -t ext3 /dev/loop0 filesystem
cd filesystem
cp ../script.sh ./
sh script.sh
echo "Formating ext4 filesystem"
mkfs -t ext4 /dev/loop0
mount -t ext4 /dev/loop0 filesystem
cd filesystem
cp ../script.sh ./
sh script.sh
echo "Formating XFS filesystem"
mkfs -t xfs -f /dev/loop0
mount -t xfs /dev/loop0 filesystem
cd filesystem
cp ../script.sh ./
sh script.sh
echo ""Formating ReiserFS filesystem"
mkfs.reiserfs /dev/loop0
mount -t reiserfs /dev/loop0 filesystem
cd filesystem
cp ../script.sh ./
sh script.sh

creara un archivo de 5gb que utilizara como disco duro (enlazado con /dev/loop0) para ejecutar la siguiente batería de pruebas.

Prueba 1: Crear 10000 ficheros


mkdir fileDir
echo "Creating Files"
date --rfc-3339=ns
for i in {1..10000}
do
touch fileDir/$i
done
date --rfc-3339=ns

create 10000 filesen esta prueba XFS se lleva la peor parte en esta parte posiblemente a causa de las write barriers que lo obliga a escribir en el disco mas veces de las necesarias, encfs a pesar de estar encriptado no se ve penalizado. Los otros sistemas de archivos tienen un rendimiento similar.

Prueba 2: Buscar dentro de los 10000 ficheros

echo "Finding Fluzo generator"
 date --rfc-3339=ns
 for i in {1..10000}
 do
 grep "fluzo"  fileDir/$i
 done
 date --rfc-3339=ns

find a file

Esta prueba obliga al sistema abrir todos los archivos para buscar en su contenido la palabra “fluzo”, el retraso de encfs se debe por su penalización al estar encriptado el resto de sistemas de archivo no tienen una diferencia de rendimiento destacable siendo XFS y btrfs un poco mas lentos que la familia ext y reiserFS

Prueba 3: Eliminar los archivos de la prueba 1

echo "Removing File Directory"
 date --rfc-3339=ns
 rm -rf fileDir
 date --rfc-3339=ns

Remove file directory

XFS se lleva la peor parte en esta prueba siendo extremadamente lento (¿write barriers?) , encfs también sufre una pequeña penalización  pero no es tan destacable como el XFS  los sistemas de archivos que utilizan un árbol como estructura sufren una mayor penalización que los que usan una lista.

Prueba 4: Buscar en una estructura de 10000 directorios

mkdir dirDir
 echo "Creating Directories"
 cd dirDir
 for i in {1..10000}
 do
 mkdir $i
 done
 cd ..
 echo "Finding Fluzo into directory struct"
 date --rfc-3339=ns
 find fluzo
 date --rfc-3339=ns

find a file into directory struct

Esta prueba obliga al kernel a abrir el contenido de todos los directorios y buscar en sus estructuras. Los arboles B+ de ReiserFs le otorgan una alta ventaja  frente al resto siendo el mas eficiente el encfs el perdedor es ext3

Prueba 5: Eliminar 10000 directorios

echo "Removing Directories"
 date --rfc-3339=ns
 rm -rf dirDir
 date --rfc-3339=ns

remove 10000 directories

La operaciones de eliminación de ficheros son mas rápidas en ext2 sobre el resto de los ficheros, los otros sistemas se ven penalizados al balancear los arboles el sistema encfs sufre una altisima penalización

Prueba 6: Copiar el kernel desde el directorio home del usuario

echo "Copying Kernel from user home"
 date --rfc-3339=ns
 cp ~/kernel.tar.gz ./
 date --rfc-3339=ns

copy kernel from user home

La copia de un archivo grande muestra que tanto ext3 como ext2 no pueden alardear de un gran rendimiento el resto de sistemas de archivos realizan la misma acción en menos tiempo (casi la mitad) a excepción de Encfs que queda en un puesto intermedio

Prueba 6: Copiar el kernel al home del usuario

echo "Copying Kernel to user home"
 date --rfc-3339=ns
 cp kernel.tar.gz ~/kernel2.tar.gz
 date --rfc-3339=ns
 rm -rf ~/kernel2.tar.gz

copy kernel to user home

La siguiente prueba obliga al sistema a realizar una lectura del sistema del archivo copiado en el paso anterior XFS aparece como el vencedor en cuanto a rendimiento seguido de ext2 y btrfs el resto de sistemas de archivos muestran un retraso considerable al realizar la lectura siendo el mas lento ext3

Prueba 7 : Descomprimir el tarball del kernel

echo "Untar Kernel source"
 date --rfc-3339=ns
 tar -xzf kernel.tar.gz
 date --rfc-3339=ns

untar kernel

La descompresión del tarball del kernel obliga al sistema de archivo a crear un gran numero de directorios y sus archivos XFS vuelve a ser el mas lento, y ext2 el mas rapido,  ext3,ext4  y reiserFS se aproximan al rendimiento de ext2 quedando btrfs un poco descolgado y encfs en un punto intermedio

Prueba 8: Comprimir el codigo fuente del kernel

echo "tar Kernel source"
 date --rfc-3339=ns
 tar -czf paquete.tar.gz linux-2.6.32/
 date --rfc-3339=ns

tar kernel source

Esta prueba combina la lectura de todos los archivos del kernel con la creación de un nuevo archivo en el caso de XFS su velocidad de lectura compensa su lentitud de escritura teniendo todos los sistemas un rendimiento simila a excepciçon de encfs que se vuelve a mostrar como el mas lento de todos

Prueba 9: Eliminar la carpeta que contiene el codigo del kernel

echo "Removing Kernel Source Tree"
 date --rfc-3339=ns
 rm -rf linux-2.6.32
 date --rfc-3339=ns

remove kernel source tree

Esta prueba obliga al sistema de archivos a eliminar un gran conjunto de archivos y directorios. ext4 es el mas rapido con diferencia y XFS se perfila como el sistema mas lento de todos los demas sistemas de archivos muestran un rendimiento un poco mas lento que ext4 (entre 2 y 4 veces mas lentos).

Prueba 10: Copiar 10 veces el tarball del kernel

echo "Copying 10 times kernel tarball"
 date --rfc-3339=ns
 for i in {1..10}
 do
 cp paquete.tar.gz paquete.tar.gz.$i
 done
 date --rfc-3339=ns

copy ten times kernel tarball

En esta prueba obligamos al sistema de archivos a crear 10 archivos de tamaño mediano leyendo un archivo localizado en el mismo sistema de archivos, reiserFS es el mas rapido aunque pero no llefa a ser doblado por ninguno de los otros sistemas de archivos a excepción de Encfs.

Prueba 11: Crear un archivo de 1Gb

echo "Creating a 1GB file"
 date --rfc-3339=ns
 dd if=/dev/zero of=gigafile.file count=2097152
 date --rfc-3339=ns

create 1GB file

En esta prueba llenamos 1/5 parte del sistema de ficheros con un unico archivo siendo los rendimientos similares ganando XFS y el resto de los sistemas teniendo unos retrasos no mayores que el doble en el caso de ReiserFS y Ext3, encfs sigue demostrando que es el mas lento con diferencia (4 veces mas lento aprox).

Prueba 12: Copiar el archivo de 1Gb creado en la prueba anterior

echo "Copying gigafile"
 date --rfc-3339=ns
 cp gigafile.file newgigafile.file
 date --rfc-3339=ns

copy a gigabite file

En esta prueba obligamos al sistema de archivos a leer 1/5 parte de su contenido y a escribirla en otro archivo btrfs es el mas rapido con diferencia seguido de ext4 y a lo lejos por XFS tanto ext2, ext3 y reiser son los menos apropiados para trabajar con archivos tan grandes. encfs tiene un rendimiento lento quedando en un punto intermedio, posiblemente al usarse sobre un sistema ext4.

Prueba 13: Separar un archivo en varias partes de distintos tamaños

dd if=/dev/zero of=tosplit.img count=20480
 mkdir splitDir
 echo "Spliting 10 Mb file"
 date --rfc-3339=ns
 split -b 1000 -d tosplit.img splitDir/mi_split1000.s
 split -b 1024 -d tosplit.img splitDir/mi_split1024.s
 split -b 2048 -d tosplit.img splitDir/mi_split2048.s
 split -b 4096 -d tosplit.img splitDir/mi_split4096.s
 split -b 8192 -d tosplit.img splitDir/mi_split8192.s
 date --rfc-3339=ns

split 10 MB file

En esta prueba se obliga al sistema a duvidir un fichero de 10Mb en  un conjunto de partes del tamalo de 1000,1024,2048,4096 y 8192 bytes, la lentitud de XFS creando archivos lo relega a ser el mas lento de todos reiserFS y ext2 quedan en un segundo grupo que tarda un poco mas del doble que el grupo de cabeza formado por btrfs,ext3 y ext4. Encfs tarda un poco mas del triple.

Prueba 14: Leer el archivo de 1Gb con cat redirigiendo la salida a /dev/null

echo "Cat 1GB file to dev/null"
 date --rfc-3339=ns
 cat gigafile.file >/dev/null
 date --rfc-3339=ns

cat 1gb file to /dev/null

En la ultima prueba obligamos al sistema de archivos a leer un archivo grande de 1Gb 1/5 el tamaño total. reiserFS muestra un rendimiento sorprendente siendo el sistema mas recomendado para lecturas de archivos grandes, seguido de btrfs con un tiempo de unas 10-15 veces mas lento mientras que el resto de sistemas de archivos quedan agrupados en unos tiempos de mas del doble que btrfs.

Podemos observar todas las pruebas juntas en la siguientes listas

All Filesystem testy los tiempos totales de todas las operaciones juntas

total time filesystempara un uso mixto los mas recomendables son btrfs y ext4 seguidos de reiser y ext2 junto a ext3 encfs se perfila como uno de los mas lentos y menos recomendable.

podiamos clasificar los 3 mejores en la siguiente lista:

  • creación ficheros:     reiserFS, ext4
  • eliminación ficheros: reiserFS, ext4
  • lectura de ficheros: ext2, btrfs,xfs (grandes)

Las siguientes pruebas no han tenido en cuenta características como journaling, capacidades de encriptación, rendimiento en configuraciones RAID y sistemas de archivos con mucho movimiento donde aparezcan penalizaciones por fragmentación.

Listas simplemente enlazadas

Escribir un programa en C que define una estructura de una listas enlazada single.
Este lista enlazada debe contener un campo entero, denominada “pid”,
y también un campo de tipo array estatica denominada mem[], representando algo no especificada.
A continuación, escribe funciones que van a realizarlas siguientes operaciones fundamentales con este estructura:

  • crear un elemento que inicializa cada uno de los campos
  • insertar un nuevo elemento al principio (a la cabecera) de la lista
  • insertar un nuevo elemento al final (a la cola) de la lista
  • un iterador que es capaz de imprimir cada uno de los campos de cada elemento y también imprime cada uno de los elementos del array estática, mem[], correspondiente.
  • Eliminar un elemento de la lista a través del valor del pid

No es la solución mas elegante pero mi C se estaba oxidando demasiado

entrega_1_ASO

Examen etc Xuño 2009

O sumador binario completo tarda 8 ns en facer a  suma de 2 operandos de 1 bit. Cánto tardaría un sumador paralelo para operandos de 16 bits?

a) 64 ns
b) 256 ns
c) 128 ns
d) Depende do tempo de propagación do acarreo

16 operandos de un bit necesitan 16 sumadores de 8 ns 16*8ns=128ns

O tamaño do Rexistro de estado, de sinalizadores, ou de flags (RF)

a) Ten o mesmo tamaño que a palabra que manexa o procesador
b) Ten o mesmo tamaño que o bus de direccións
c) Ten un tamaño de 2n, sendo n o número de sinalizadores do RF
d) Ningunha das respostas anteriores é correcta

Ten o mismo tamaño que a palabra porque no 8085  “Flag is an 8-bit register containing 5 1-bit flags:”

Dada a seguinte instrucción da máquina 8085: LDA 7AB5h Cál será a súa codificación, expresada en notación hexadecimal?

a) 3AB57Ah
b) 3A7AB5h
c) 2AB57A
d) Ningunha das respostas anteriores é correcta

Na instrucción da máquina 8085: ADD M Qué tipo de direccionamento leva o operando destino?

a) Directo
b) Indirecto a parella de rexistros
c) Por rexistro
d) Ningunha das respostas anteriores é correcta

¿Cántos bloques de memoria de 16Kx8 se necesitan para formar unha memoria de 32Kx32?

a) 8
b) 4
c) 16
d) É imposible construir esa memoria con bloques de 16Kx8

32*32= 1024 | 16*8=128 | 1024/128=8

Un procesador manexa unha memoria de 128Mx64. Cál debería ser o tamaño do rexistro contador de programa, PC?

a) 24
b) 27
c) 32
d) Todas as afirmacións citadas son incorrectas

Un procesador A ten unha ƒ= 5 MHz e un CPI=10 o utro pocesador B ten unha ƒ=10 MHz e un CPI= 5. Pon unha X na resposta correcta

a) O procesador A é máis rápido que o B
b) O procesador B é máis rápido que o A
c) Ambos teñen a mesma velocidade
d) Faltan datos para contestar a pregunta

Dada a seguinte situación para o 8085: SP=200h; (B-C)= 345Ah; (D-E)= A67Eh; (H-L)= 2B50h. Despois de realizar as instruccións: PUSH B; PUSH D e PUSH H Cál será o contido da dirección de memoria: 01FBh.

a) 7Eh
b) 50h
c) 2Bh
d) Ningunha das respostas anteriores é correcta

En cál dos seguintes casos, o ancho de palabra ou tamaño das posicións de memoria de control (MC) é menor?

a) Nunha MC microprogramada con secuenciamento explícito
b) Nunha MC microprogramada con secuenciamento implícito
c) É igual en ámbalas dúas
d) Ningunha das respostas anteriores é correcta

Sabendo o contido dos rexistros A=54h, B=37h, C=8Eh, F=54H e que o das posicións de memoria coincide coa parte baixa da súa propia dirección, indicar o contido final de A e F despois de executar a instrucción: LDAX B

a)   A= 37h    F= 54h
b)   A= 8Eh    F= 54h
c)   A= 8Eh    F= 45h
d) Ningunha das respostas anteriores é correcta

rrrr

parte 8085 examen Xuño 2009 ETC

Dados 3 números N1,N2,N3, situados en tres direccións consecutivas de memoria.
PIDESE:
a) Ordinograma, orientado para o 8085, e codificación co ensamblador da mesma, do
algoritmo que conte cantos de eses tres números son iguais. O resultado gardarase
nunha posición de memoria denominada RESTDO. (3 puntos)
b) ¿Cántas instrucións ocupa o programa?. (0,5 puntos)
c) ¿Cántos bytes ocupa o programa?. (0,5 puntos)
d) No caso de que os tres números fosen iguais, que a maquina teña unha fecuencia de
10 MHz, e que inverte na execución do programa 4 microsegundos, ¿Cál e o CPI medio
para este programa?. Márquense, con *, no ordinograma e no programa codificado
as instrucións que se executan. (1 punto)

a)

Organigrama
Organigrama

;Assembler generated listing. Do not hand edit and assemble
;<Compara 3 numeros>
4200 C3 0F 042   jmp carga

;data
4203   03 (1 bytes)    Tamano: db 3h ;tamaño do array que conten os numeros
4204   00 (1 bytes)    PasoTam: db 0h ;valor do tamaño +1
4205   00 (1 bytes)    Comparador: db 0h ;posicion do array do numero que se esta comparando
4206   00 (1 bytes)    Comparados: db 0h ;posicion do array do numero co que comparamos
4207   00 (1 bytes)    RESTDO: db 0h ;contador de numeros iguais
4208   02 (1 bytes)    N1: db 2 ;numero 1
4209   02 (1 bytes)    N2: db 2 ;numero 2
420A   02 (1 bytes)    N3: db 2 ;numero 3
420B   00 (1 bytes)    Hcmpdor: db 0h; rexistro h do comparador
420C   00 (1 bytes)    Lcmpdor: db 0h; rexistro l do comparador
420D   00 (1 bytes)    Hcmpdo: db 0h;  rexistro h do comparado
420E   00 (1 bytes)    Lcmpdo: db 0h;  rexistro l do comparado

;code.
420F 3A 03 042   carga: lda Tamano;cargamos a variable tamanho
4212 4F  mov c,a ;cargamos a variable tamaño no rexistro C
4213 3C  inr a ;incrementamola en 1
4214 32 04 042   sta PasoTam ; gardamos a marca de paso de tamaño
4217 21 08 042   lxi h,N1;cargamos a direccion de N1 en HL
421A 7C  mov a,h
421B 32 0B 042   sta Hcmpdor
421E 32 0D 042   sta Hcmpdo
4221 7D  mov a,l
4222 32 0C 042   sta Lcmpdor
4225 32 0E 042   sta Lcmpdo
4228 54  mov d,h
4229 5D  mov e,l ;copiamos a direccion en HL
422A 3E 01  mvi a, 1h;
422C 32 05 042   sta Comparador
422F 32 06 042   sta Comparados
4232 C3 50 42   jmp AuCmpdos
4235 3A 05 042   AuCmpdor: lda Comparador
4238 3C  inr a
4239 32 05 042   sta Comparador
423C 32 06 042   sta Comparados
423F B9  cmp c;Verificamos si Comparador es el ultimo numero
4240 CA B5 42   jz fin ; saltamos si hemos llegado al final
4243 3A 0C 042   lda Lcmpdor
4246 3C  inr a
4247 CA 92 42   jz aumentaHdor ; si L se pasa temos que aumentar H
424A 32 0C 042   sta Lcmpdor
424D 32 0E 042   sta Lcmpdo
4250 3A 06 042   AuCmpdos: lda Comparados
4253 3C  inr a
4254 32 06 042   sta Comparados
4257 FE 04  cpi PasoTam;Verificamos se pasamos o array para adiante
4259 CA 35 42   jz AuCmpdor
425C 3A 0E 042   lda Lcmpdo;Si non aumentamos a lo do comparador
425F 3C  inr a
4260 CA A8 42   jz aumentaHdo
4263 32 0E 042   sta Lcmpdo
4266 3A 0D 042   compara: lda Hcmpdo
4269 67  mov h,a
426A 3A 0E 042   lda Lcmpdo
426D 6F  mov l,a
426E E5  push h
426F 46  mov b,M ;cargamos en o numero comparado
4270 3A 0B 042   lda Hcmpdor
4273 67  mov h,a
4274 3A 0C 042   lda Lcmpdor
4277 6F  mov l,a
4278 E5  push h
4279 7E  mov a,M
427A B8  cmp b
427B CA 84 42   jz aumentaRESTDO
427E C3 50 42   fincomp: jmp AuCmpdos
4281 D2 35 42   jnc AuCmpdor; aumentamos o comparador en caso de que pasaramos o array
4284 00  aumentaRESTDO: nop
4285 3A 07 042   lda RESTDO
4288 3C  inr a
4289 32 07 042   sta RESTDO
428C C3 7E 42   jmp fincomp

428F C3 B5 42   jmp fin
4292 00  aumentaHdor: nop
4293 3A 0B 042   lda Hcmpdor
4296 3C  inr a
4297 32 0B 042   sta Hcmpdor
429A 32 0D 042   sta Hcmpdo
429D 3E 00  mvi a, 0h
429F 32 0C 042   sta Lcmpdor
42A2 32 0E 042   sta Lcmpdo
42A5 C3 66 42   jmp compara
42A8 00  aumentaHdo: nop
42A9 3A 0D 042   lda Hcmpdo
42AC 3C  inr a
42AD 32 0D 042   sta Hcmpdo
42B0 3E 00  mvi a, 0h
42B2 32 0E 042   sta Lcmpdo
42B5 76  fin: hlt

En el simulador no me daba ningun problema gnusim8085el dia que tenga paciencia lo acabo de hacer o sino podeis corregirme en los comentarios

Examen Calculo Esei Febrero 2006

Examen B Calculo

Escola Superior de

Enxeñeria Informatica Ourense (ESEI)

Profesor: Rosario Pereira

  1. Regla de L’Hopital: enunciado, demostración, comentarios.
  2. Comprobar que la ecuación examen calculo preg 2 tiene una raiz entre 1 y 2. Calcular el valor aprximado de esa raiz con error menos de 0,25.

  3. En la ecuación examen_calculo_febrero_esei_3, substituir la funcion arctan por una aproximación polinomica adecuada de grado 3 y resolver.

  4. Hallar las asintotas y ramas parabolicas de la curva dada por examen_calculo_febrero_esei_4

  5. Calcular si es posible

    a) examen_calculo_febrero_esei_5a

    b) examen_calculo_febrero_esei_5b

    c) examen_calculo_febrero_esei_5c

  6. Estudiar la convergencia de las series

    a)examen_calculo_febrero_esei_6a

    b)examen_calculo_febrero_esei_6b

    c)examen_calculo_febrero_esei_6c