Páginas

jueves, 3 de septiembre de 2015

Creando un cronometro para medir tiempo de ejecución de nuestros metodos

Hubo muchas veces que por cuestiones de perfomance necesitaba saber el tiempo de respuesta de cada invocación a un método, por ejemplo muchas veces sobre consultas a bases de datos. 

Cansado de usar la clase StopWatch y repetir siempre la misma lógica , decidí crearme un cronometro para tomar el tiempo de cualquier método. El post lo voy a hacer breve, así que explico rápidamente algunas características y al final esta el ejemplo para descargar: 


  • Clase Cronometro con 3 métodos estáticos TomarTiempo, la respuesta a la toma del tiempo es una instancia de la clase CronometroResultado que contiene un TimeSpan (fraccion de tiempo) , resultado del método invocado y un flag que indica si el metodo fue encontrado.
  • Soporte para metodos con y sin parámetros.
  • TomarTiempo se encarga de buscar el metodo por nombre y coincidencia de cantidad y tipo de parametros.
  • Busquedas usando Reflection.
  • Aun no tiene soporte para métodos genéricos.
  • No importa el orden en que se envian los parametros, TomarTiempo se encarga de buscar el coincidente.

La verdad que me resulta mucho mas comodo ahora medir los ticks, milisegundos , segundos ,etc con esta forma , acá va la clase completa y como dije al final el fuente ..... lo demas para que lo investiguen ... 




Clase Cronometro ....


  public class Cronometro
    {

        /// 
        /// Usar esta carga para invocar metodos de instancia
        /// 
        /// Tipo de la clase que contiene el metodo. Ejemplo: typeof(MiClase)
        /// Nombre del metodo, no es case sensitive
        /// Array de object con los parametros que se le pasaran al metodo encontrado
        /// CronometroResultado
        public static CronometroResultado TomarTiempo(object instance, string nombreMetodo, object[] arguments)
        {
            return TomarTiempo(instance.GetType(), instance, nombreMetodo, arguments);
        }

        /// 
        /// Usar esta carga para invocar metodos estaticos
        /// 
        /// Tipo de la clase que contiene el metodo. Ejemplo: typeof(MiClase)
        /// Nombre del metodo, no es case sensitive
        /// Array de object con los parametros que se le pasaran al metodo encontrado
        /// CronometroResultado
        public static CronometroResultado TomarTiempo(Type type, string nombreMetodo, object[] arguments)
        {
            return TomarTiempo(type, null, nombreMetodo, arguments);
        }

        internal static CronometroResultado TomarTiempo(Type tipo, object instance, string nombreMetodo, object[] arguments)
        {

            MethodInfo ejecutar = null;


            bool searchStatics = instance == null;

            nombreMetodo = nombreMetodo.ToLower();

            //buscar dentro de los metodos encontrados si alguno coincide con los parametros enviados
            MethodInfo[] metodos =
                tipo.GetMethods().Where(m => m.Name.ToLower() == nombreMetodo & m.IsStatic == searchStatics).ToArray();

            //Soporte para metodos que no tienen parametros de entrada 
            if (arguments == null || arguments.Length == 0)
            {
                ejecutar = metodos.Where(m => m.GetParameters().Length == 0).FirstOrDefault();
            }
            else
            {
                //entre todos los metodos busco los parametros que coincidan
                foreach (var met in metodos)
                {
                    ParameterInfo[] pars = met.GetParameters();

                  
                    //coincide busco el orden de los parametos
                    if (pars.Length == arguments.Length )
                    {

                        Int16 coincidencias = 0;
                        for (int i = 0; i < pars.Length; i++)
                        {
                            if (pars[i].ParameterType.Name == arguments[i].GetType().Name)
                            {
                                ++coincidencias;
                            }
                        }

                        if (coincidencias == pars.Length)
                        {
                            ejecutar = met;
                            goto continuar;
                        }
                    }
                }

            }

            continuar:

            CronometroResultado resultado = new CronometroResultado();
            Stopwatch reloj = new Stopwatch();

            if (ejecutar != null && !ejecutar.IsGenericMethod)  //sin soporte para genericos
            {
                reloj.Start();
                resultado.Resultado = ejecutar.Invoke(instance, arguments);
                reloj.Stop();
                resultado.MetodoEncontrado = true;
            }

            resultado.Tiempo = reloj.Elapsed;
            return resultado;
        }


    }

Clase CronometroResultado ....


 public class CronometroResultado
    {

        private TimeSpan _span;

        public bool MetodoEncontrado { get; set; }

        public TimeSpan Tiempo
        {
            get { return _span; }
            set
            {
                _span = value;
            }
        }

        public object Resultado { get; set; }

    }


Una pruebita al metodo Vender de la clase Venta ... 



            Venta v = new Venta();
            var res = Cronometro.TomarTiempo(v, "vender", new object[] { 1, 2 });
            Console.WriteLine("Resultado ejecución");
            Console.WriteLine("--------------------");
            Console.WriteLine(res.MetodoEncontrado ? "Encontrado" : "No encontrado");
            Console.WriteLine("Ticks: " + res.Tiempo.Ticks.ToString());
            Console.WriteLine("Milisegundos: " + res.Tiempo.Milliseconds.ToString());
            Console.WriteLine("Segundos: " + res.Tiempo.Seconds.ToString());
            Console.WriteLine("Resultado: " + res.Resultado);
            Console.WriteLine("");
            Console.WriteLine("");

Espero que sirva ... aca el ejemplo Descargar