Matar proceso segun su uso de cpu o memoria ram Window 7

Iniciado por eleze, 4 Enero 2018, 09:34 AM

0 Miembros y 2 Visitantes están viendo este tema.

eleze

Que tal compañeros! Es un placer para mi llegar hasta aqui despues de buscar y buscar toda la semana y probar hasta 12 programas! sugeridos de este asunto.
Sin duda la conclusion que llege es que se presisa de un sabio en la materia
Aunque todos ustedes saben mucho cada cual tine su punto fuerte y asi todo aportan para la solucion. Permitanme este cumplido por favor.
El asunto es
¿Como podria programar un codigo o script para analizar los procesos continuamente y Matar un proceso segun su uso de cpu o memoria ram?
Es decir cuando un proceso por eje del chrome supere x cantidad de uso de ram...

Estuve viendo los scipt Vb tal vez...???
Estoy a su dispocicion para aclarar motivos y circunstancias en lo posible.
Muchas Gracias a todo el que dese ayudar.

Eleкtro

#1
Cita de: eleze en  4 Enero 2018, 09:34 AM
Que tal compañeros! Es un placer para mi llegar hasta aqui despues de buscar y buscar toda la semana y probar hasta 12 programas! sugeridos de este asunto.
Sin duda la conclusion que llege es que se presisa de un sabio en la materia

No se merece calificar de "sabio en la materia" a nadie por tal cosa, me refiero a que no hace falta ser un gurú, es algo bastante sencillo de realizar. Puedes usar los contadores de rendimiento de Windows en cualquier lenguaje que te permita hacerlo, por ejemplo en C# o VB.NET, o en su defecto cualquier lenguaje que te permita realizar consultas a WMI (concretamente a la clase 'Win32_PerfFormattedData_PerfProc_Process' para leer la propiedad 'PercentProcessorTime')... que viene a ser practicamente lo mismo.

Te muestro un ejemplo básico y adaptable escrito en VB.NET para obtener el porcentaje de uso de CPU del proceso notepad.exe:

Código (vbnet) [Seleccionar]
Using p As Process = Process.GetProcessesByName("notepad").Single(),
     perf As New PerformanceCounter("Process", "% Processor Time", p.ProcessName, True)

   ' http://msdn.microsoft.com/en-us/library/system.diagnostics.performancecounter.aspx
   perf.NextValue()
   Thread.Sleep(TimeSpan.FromSeconds(1)) ' Tiempo de espera para la siguiente actualización.

   Dim msg As String =
       String.Format("Process Name: {0}; CPU Usage: {1}%",
                     p.ProcessName, (Math.Round(perf.NextValue() / Environment.ProcessorCount, 1)))


   Console.WriteLine(msg)
End Using


primero hay que activar el uso de los contadores de rendimiento en el archivo de manifiesto de nuestra aplicación:
Código (xml) [Seleccionar]
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
...
 <system.net>
   <settings>
     <performanceCounters enabled="true"/>
   </settings>
 </system.net>
...
</configuration>


Solo me he enfocado en la parte que te podría resultar más complicada de resolver, ya que "listar" (u obtener un array con) todos los procesos y matar un proceso específico es algo demasiado  sencillo y básico como para merecerse una explicación en profundidad (si necesitas formular la pregunta, puedes buscar en Googlé y hallarás la respuesta, miles de respuestas...)

En fin, como ves "la parte dificil" no es algo dificil, pero si que es necesario tener un mínimo de práctica y conocimiento previo sobre algún que otro concepto que concierne a Windows y al dominio (a nivel usuario) de "X" lenguaje de programación que vayas a utilizar para intentar llevar a cabo este tipo de cosas; con preguntar y esperar a que te lo den todo hecho en el lenguaje que sea... no es suficiente.

Con respecto al lenguaje de scripting VBS, yo personálmente no te lo recomiendo teniendo otro lenguaje nativamente soportado en Windows y mucho más sofisticado como es PowerShell, o diréctamente uno de los ya mencionados lenguajes C# y VB.NET del cual te he mostrado un ejemplo puesto que pareces estar abierto a optar por el lenguaje que sea (y yo he considerado que VB.NET es la mejor elección en tu caso si te sientes cómodo con la sintaxis VB-like como parece ser, de lo contrario, C#), pero si prefieres optar por el camino de VBS entonces te hago saber que en VBS por supuesto puedes realizar consultas a WMI, puedes busca ejemplos en Google... los hay a montones, como este:
o este:

Saludos!








eleze

Gracias Eleкtro! Esta es mi situacion. Soy sincero. Yo no se practicamente nada y usted se nota que sabe bastante. Y tiene razon, lo que para mi es una Montaña para usted es ....  no se, jeje.. por eso mis respetos y de acuerdo con usted de que la incentiva al conocimiento es la mejor arma para hacerle frente al problema.
El caso es que me di a la tarea y ya tengo algunos codigos de ejemplos sobre la lista de procesos y como matarlos en VB.NET como me sugirió (jeje le escribo como si me hubieran retado). Bueno, pasa que ahora mismo no sabria como pegar los codigos de forma correcta y fucionarlos con su ejemplo de arriba. Perdon por esto:

Lista de procesos

CitarModule Module1
    Sub Main()
        ' Get processes.
        Dim processes() As Process = Process.GetProcesses()
        Console.WriteLine("Count: {0}", processes.Length)

        ' Loop over processes.
        For Each p As Process In processes

            ' Display process properties.
            Console.WriteLine(p.ProcessName + "/" + p.Id.ToString())
        Next
    End Sub
End Module

Output

process*/id
...
Matar procesos

CitarPrivate Sub Button6_Click(ByVal sender As System.Object, ByVal e As DevComponents.DotNetBar.ClickEventArgs)
    Timer1.start()
End Sub

Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
    For Each prog As Process In Process.GetProcesses
        If prog.ProcessName = "ProcessName" Then
                prog.Kill()
        End If
    Next

Aún no lo entiendo todo, pero seguiré haciendo el esfuerzo, por favor siganme ayudando. Si desean puedo explicar mas detalles porque la idea seria que se ejecutara en bucle automaticamente al iniciar window.
Gracias!!

Eleкtro

#3
Cita de: eleze en  5 Enero 2018, 10:23 AM
El caso es que me di a la tarea y ya tengo algunos codigos de ejemplos sobre la lista de procesos y como matarlos en VB.NET como me sugirió (jeje le escribo como si me hubieran retado).

Pues para no saber practiamente nada, con una simple recomendación (o "reto" xD) ya has hecho mucho más de lo que otros han hecho en tu misma situación... ¡se nota que te esfuerzas en resolver las cosas!... y con las cosas que vayas aprendiendo poco a poco haciendo eso. EDITO: pero si veo que incluso estás usando el framework de DotNetBar, ¿seguro que nunca antes habias programado en VB.NET? xD.

Cita de: eleze en  5 Enero 2018, 10:23 AMno sabria como pegar los codigos de forma correcta y fucionarlos con su ejemplo de arriba

Bueno, eso depende del objetivo que tengas en mente... debes adaptar el ejemplo que te mostré, a tus necesidades.

He escrito este otro ejemplo algo más extenso por si te sirve de mejor ayuda, aunque no se si te voy a conseguir ayudar o por lo contrario voy a conseguir confundirte...puesto que en el código hago uso de técnicas de programación asincrónica mediante la aplicación del paralelismo para acelerar el procedimiento de ejecución (puesto que la función GetProcessCPUPercentUsage necesariamente es una llamada bloqueante de 500-1000 ms, y no queremos tener que esperar 500-1000 ms por cada proceso que haya...¿verdad que no?, jeje).  

...nótese que declaré una variable en la que especifico que el máximo válido de porcentaje de CPU para un proceso es 6.0%; si el límite se sobrepasa, se intenta matar al proceso.

Código (vbnet) [Seleccionar]
Imports System
Imports System.Collections.Concurrent
Imports System.Collections.Generic
Imports System.Diagnostics
Imports System.Linq
Imports System.Threading
Imports System.Threading.Tasks

Public Module Module1

   Public Sub Main()
       Dim maxCpuUsage As Double = 6.0R '%

       ' White-listed process names.
       Dim whlNames As IEnumerable(Of String) =
           {
             "csrss", "dwm", "fontdrvhost", "idle", "lsass", "runtimebroker",
             "services", "sihost", "smss", "svchost", "System", "taskhostw",
             "wininit", "winlogon"
           }

       ' Current processes sequence.
       Dim prcsQuery As ParallelQuery(Of Process) =
           (From prc As Process In Process.GetProcesses()
            Where Not whlNames.Contains(prc.ProcessName, StringComparer.OrdinalIgnoreCase)
           ).AsParallel().AsUnordered()

       Dim action As New Action(Of Process)(
           Sub(prc As Process)
               If (prc Is Nothing) Then
                   Exit Sub
               End If

               Dim cpuPercent As Double = GetProcessCPUPercentUsage(prc)
               Dim pName As String = prc.ProcessName
               Dim pid As Integer = prc.Id

               If (cpuUsage < maxCpuUsage) Then
                   Console.WriteLine(String.Format("[ GOOD ] Name: {0}; PID: {1}; CPU: {2}%", pName, pid, cpuPercent))

               Else
                   Console.WriteLine(String.Format("[ BAD  ] Name: {0}; PID: {1}; CPU: {2}%", pName, pid, cpuPercent))
                   Console.WriteLine(String.Format("[ ...  ] Attempting to kill process '{0}' with PID '{1}'...", pName, pid))

                   Try
                       If Not (prc.HasExited) Then
                           prc.Kill()
                       End If
                       Console.WriteLine("[ ...  ] Process was killed successfuly.")

                   Catch ex As Exception
                       Console.WriteLine("[ ...  ] Error trying to kill process...")
                       Throw

                   End Try
               End If

           End Sub)

       Parallel.ForEach(Of Process)(prcsQuery, New ParallelOptions(), action)
   End Sub

   Friend Function GetProcessCPUPercentUsage(ByVal p As Process) As Double
       Using perf As New PerformanceCounter("Process", "% Processor Time", p.ProcessName, True)
           perf.NextValue()
           Thread.Sleep(TimeSpan.FromMilliseconds(500)) ' Recommended value: 1 second
           Return (Math.Round(perf.NextValue() / Environment.ProcessorCount, 1))
       End Using
   End Function

End Module


Resultado de ejecución:
...

[ GOOD ] Name: GameOverlayUI; PID: 7404; CPU: 0,2%
[ GOOD ] Name: sidebar; PID: 4836; CPU: 0,3%
[ GOOD ] Name: ScriptedSandbox64; PID: 9552; CPU: 0,3%
[ GOOD ] Name: BEService; PID: 10952; CPU: 0,4%
[ BAD  ] Name: ShooterGame; PID: 5136; CPU: 6,3%
[ ...  ] Attempting to kill process 'ShooterGame' with PID '5136'...
[ ...  ] Process was killed successfuly.
[ GOOD ] Name: Start10_64; PID: 2576; CPU: 0%
[ GOOD ] Name: CTAudSvc; PID: 1916; CPU: 0,1%
[ GOOD ] Name: NVDisplay.Container; PID: 1184; CPU: 0%

...


PD: si quieres ordenar las lineas de salida por el nombre del proceso... es algo que requeriría modificar casi por completo el código del ejemplo, en cuyo caso no debes intentar ordenar la secuencia paralela, en su lugar declara una clase o estructura para representar la información necesaria de un proceso (el nombre, PID, y porcentaje de cpu) a la que podriamos llamar "ProcessInfo", entonces creas una nueva colección genérica de tipo List(Of ProcessInfo) (o bien un SortedSet(Of ProcessInfo) pasándole un IComparer(Of ProcessInfo), primero deberías crear el comparer), y el bloque del Parallel.ForEach( ... ) (el método declarado en la variable "action") lo usarías solamente para obtener el porcentaje de cpu e ir añadiendo elementos "ProcessInfo" a la lista, ordenarla, y por último ya podrías iterar la lista de forma ordenada. Se que sin mostrar un ejemplo de código, estas explicaciones no serán muy fáciles de entender o de aplicar, pero tampoco se lo que quieres hacer exactamente, ni si necesitas mosrar los resultados en consola, ni si necesitas hacerlo de forma ordenada, y ponerme a escribir variaciones de un mismo código sin saber cual te va a servir... es tontería hacerlo xD.

Saludos!








eleze

 ;-) ;-) ;-) ;-) ;-) ;-) ¡Sin palabras, que más puedo decir! ;-) ;-) ;-) ;-) ;-) ;-)
Cita de: Eleкtro en  5 Enero 2018, 15:49 PMaunque no se si te voy a conseguir ayudar o por lo contrario voy a conseguir confundirte...puesto que en el código hago uso de técnicas de programación asincrónica mediante la aplicación del paralelismo para acelerar el procedimiento de ejecución
Lo que siento es lo que veo, Senciillez en las variables, declaraciones ordenadas y claras, con solo decirle que ni siquiera utilizó las de tipo genericos como "As Object". Jeje, y yo usandolas para matar un simple proceso.
Y noté aún más, su acto gentil, llamelo bondad si quiere...
Cita de: Eleкtro en  5 Enero 2018, 15:49 PM(puesto que la función GetProcessCPUPercentUsage necesariamente es una llamada bloqueante de 500-1000 ms, y no queremos tener que esperar 500-1000 ms por cada proceso que haya...¿verdad que no?, jeje).
...muy idoneo ya que acelera las operaciones y a su vez menor consumo de recursos del sistema.
Creame, no trato de exagerar cuando intento darle las ¡Muchas Gracias Elektro! por su tiempo y la capacidad contructiva para brindar su ayuda. Y no hablo por mi solamente, sino por los muchos mas que habrá ayudado de la misma forma, algunos agradecidos y otros no tanto. Me conozco, me hubiese llevado 'semanas' lograr "algo" parecido y vaya a saber si funcionaria.. (jeje  :-[creo que estoy emocionado...y eso que todavia no lo eh probado :xD)
Sin olvidar agradecerle su estimulo que para mi eso hacen los compañeros (hablo bajito, de hecho ha sido el unico que respondio, supongo que el tiempo no nos da a todos por igual y lo entiendo)
En fin, prometo probarlo e ir ordenando las ideas y aclarar cual es el gran motivo...
Cita de: Eleкtro en  5 Enero 2018, 15:49 PMpero tampoco se lo que quieres hacer exactamente
...de por que debo hacer esto en la pc de casa.
Nos vemos mañana!
PD: Si mal lo recuerdo deberia colocar el script en la carpeta de Inicio de window para que comienza automáticamente con el sistema o eso es para los .bat? Talvez me estoy confundiendo yo solo ya que no vi la funcion Loop en el codigo.

Serapis

#5
Mmmmm... se te ha olvidado una cuestión importante: ¿para qué quieres hacer eso?.

Y te señalo por qué es importante.
Supongamos que tu idea es intentar bloquear "programas maliciosos", en este caso, lo más probable es que no sea efectivo al 100%. y te lo razono.
Imagina un programa malicioso, supera cierto nivel de carga de CPU y lo matas, ok... 1 minuto después ahí está otra vez... entonces aunque sea con interrupciones, su tarea sigue adelante, solo que más demorado en el tiempo.

Un programa malicioso, en general si está medianamente bien programado, no opera sólo, siempre están al acecho, son otros ejecutables los que lo lanzan y que 'pasan' por 'buenos', nada raro ni sospechoso en ellos se detecta... es decir el programa que ejecuta la tarea maliciosa, es 'contratado' por otro programa que lo pone en marcha (algo así como cuando alguien contrata un asesino para matar. Él que quiere que muera alguien y la persona que lo mata, si no quiere (ensuciarse las manos y arriegarse a) ser descubierto, es otra, no la misma. Más aún ni siquiera 'habla' directamente, con el que hace el 'trabajo sucio', si no que busca un intermediario...

Así, resumiendo: un programa malvado (A), tendrá una apariencia limpia, y su única tarea será arrancar otro programa (B). Es B, quien de cuando en cuando revisa si el programa que hace el trabajo sucio (C), está en marcha o no, y si no lo está lo manda ejecutar... Así si ya resulta difícil asociar B con C, mucho más A con C.

Luego en efecto matar un proceso, no es todo lo efectivo que es deseable si el objetivo de tu programación, es librarte de procesos 'maliciosos' o solo 'indeseables'. Debes investigar el padre del (proceso) mismo y a su vez al padre de ése y así respectivamente. A veces no es fácil, porque resulta difícl rastrear sin meterse a fondo en el tema. Un programa puede arrancarse, realizar alguna ejecución y luego pararse... al caso, entonces resulta conveniente consultar las tareas programadas... A veces incluso un programa descomprime de un archivo cifrado, otro y lo ejecuta... más aún imagina por ejemplo que tengo dos ficheros, un ejecutbale maligno y un fichero comprimido en zip, rar, 7z, etc... le das una orden de extracción al mismo y a su vez tras ser extraído, es autoejecutado (caso típico de instaladores, que descomprimen y/o decodifican y se ejecutan), tras lanzar esto se desvincula de su marcha y s epara, así la autoría incluso parecerá proceder de winrar, winzip, sevenzip, etc... para todo ello, como te decía debes meterte a fondo y suscribirte a eventos de carga de procesos, peor incluso así, hay virus que se las apañan, para saltarse el control del sistema...

En definitiva, según para qué lo quieras, lo que tienes es suficiente o te quedas a medias. Si por ejemplo tu idea es matar procesos de programas que mina (criptomonedas) en tu equipo (tan de moda en los últimos meses), si es abusivo, puede ser efectivo, pero si no pone el procesador a un nivel muy elevado (digamos que lo deja en un 3-7%), seguirá ahí latente... y si pretendes matar procesos que sobrepasen un 5%, básicamente te vas a cargar a todos, porque en algún momento, todos los programas alcanzan ese valor y lo superan intentasamente.

Sería más sensato, hacer estadísticas, es decir descubrir procesos que sobrepasen ciertos umbrales y registrarlos (nombre de procesos, valores alcanzados y tiempo que permanecen por encima de cierto umbral y frecuencia con que esto sucede), al tiempo consultar dicha estadística y sacar conclusiones... después de eso se supone que lo que hagas tendrá una lógica más acorde que la simpleza de matar al que 'se rebela'...

Por otro lado hay programas legítimos, que en algún momento dado pueden tener picos de trabajo y en general tiene programado que si se para se ponga de nuevo en marcha... hasta x veces, luego ya no se vuelve a cargar hasta la próxima sesión... pero como decía si es legítimo, puede que al matarlo estés impidiendo alguna acción absolutamente necesaria que podría incluso colgar el sistema o generar un reinicio.

...hay más tela que cortar al respecto, pero tampoco es plan de que te sientas atosigado, con toda la panoplia de características...