Rysuj za pomocą swojego procesora

289

Natknąłem się na artykuł, w którym studenci wykorzystali ruch sieciowy do narysowania swojego uniwersytetu na wykresie IPv6 w tym kraju . [wizerunek]

Twój cel jest prosty do opisania, ale trudny do zrealizowania. Narysuj tekst MAIL (ponieważ jest to jedno z niewielu słów, które można odczytać na wykresie 1D) na wykresie procesora.

Powinno to wyglądać mniej więcej tak:

Wynik

Trochę więcej pracy nad tym, co się kwalifikuje:

  • Kod nie musi być wieloplatformowy (więc nie będziesz potrzebować nieznanych API do obsługi).
  • Możesz przechwycić go w dowolnym ogólnym narzędziu do użycia procesora.
  • Wykres wygląda nieco gorzej na innym komputerze: tym razem ci ufam.
  • Podstawowy% wykorzystania procesora musi być ciągły, więc jeśli wygenerujesz losową falę i podświetlisz coś, co wygląda jak słowo MAIL, to oczywiście oszustwo.
  • Możesz wybrać maksymalne obciążenie, które chcesz użyć, ale musi ono być wystarczająco duże, aby było wyraźnie widoczne.
  • Musisz przestrzegać liniowości przykładu. (Dla M wygląda to tak:% bazy, a następnie nagły wzrost do określonego maksimum, spada stopniowo do niższego%, wznosi się z powrotem do maksimum i ponownie gwałtownie spada do podstawy%).
  • Jeśli to nieczytelne, wyborcy zauważą przecież.

Obowiązują standardowe luki. Opublikuj też zdjęcia!

bebe
źródło
9
Nie widzę już powodu do ścisłego głosowania. Osobiście uważam to za zabawne wyzwanie, choć trochę specyficzne dla systemu.
patrz
6
Problem, jaki widzę w golfie kodowym, polega na ocenie, czy czytelność jest wystarczająco czytelna. Jeśli możesz wymyślić sposób na obiektywne określenie tego, znacznie poprawiłoby to wyzwanie, ale i tak jest to naprawdę fajny pomysł!
Martin Ender
3
to tak naprawdę to samo, co twoje zdjęcie, ale gwarantuję ci, że jeśli nie wyrazisz tego słowami, ludzie będą bardzo swobodnie interpretować „narysuj MAIL”.
Martin Ender
33
+1, to takie absurdalne, że prawie zachichotałem na śmierć ... „to szaleństwo ...” „szaleństwo… TO JEST CODEGOLF !!!”
vaxquis
5
To jest cholernie niesamowite pytanie. Chciałbym być wystarczająco inteligentny, aby wziąć udział. To nie ma znaczenia, interesują mnie kreatywne rozwiązania innych osób: P
Chris Cirefice

Odpowiedzi:

117

Python, 143

from time import*
while 1:
 sleep((ord('00012345654321000~~~D:6300036:D~~~000~~~000DDDD~~~~~'[int(time())%52])-48)*0.001);x=10**5
 while x:x-=1

Każdy znak ciągu odpowiada jednej sekundzie aktywności, od znaku ASCII 0(maksymalne obciążenie) do ~(bardzo małe obciążenie). Program działa w pętli synchronizowanej czasowo, dzięki czemu można uruchamiać wiele instancji w celu uzyskania lepszych wyników.

Użyłem Pythona 2.7.6 na OS X z Intel Core i7, ale powinien on działać na innych komputerach z drobnymi poprawkami (dostosuj 0.001). Poniższy zrzut ekranu został zrobiony ze znaczną aktywnością w tle.

POCZTA

Aktualizacja - byłem w stanie stworzyć wyraźniejszy wykres przy time()/10niższej częstotliwości aktualizacji:

POCZTA

I na koniec, oto wersja bardziej golfowa ( 123 bajty ) i jej wynik :

from time import*
while 1:
 sleep((ord('002464200~~A5005A~~00~~00DDD~~'[int(time()/2)%30])-48)*0.001);x=10**5
 while x:x-=1
grc
źródło
250

Python, 358 281 268 221 194 bajtów

Monochrome jest tak w zeszłym roku. Wykorzystuje wiele procesów i wywołań systemowych, aby uzyskać dwa kolorowe wykresy procesora!

import os,time
A='%-99o'%int('t12q2lxqkap48euoej9429cstbnazl63ubyryteo49u',36)
for i in'0123456':
 t=os.fork()
 while t<1:T=int(time.time())%50;(time.sleep,(id,os.urandom)[i<A[T+49]])[i<A[T]](1)

Dane wyjściowe z Monitora aktywności (OS X 10.9):

Monitor aktywności procesora Wykres obciążenia Monitor aktywności procesora Wykres historii

Powtarza się na wykresie historii procesora

Dane wyjściowe z MenuMeters:

Wyjście MenuMeters

Wszystkie dane wyjściowe zostały wygenerowane z prędkością aktualizacji 1s. Żadne znaczące zadania w tle nie były uruchomione, ale dane wyjściowe dość łatwo pokonują jedno-wątkowe zadanie CPU.

Ten kod zakłada, że ​​masz 8 rdzeni. Powinno być dość łatwe do modyfikacji za mniej / więcej. Jest przenośny dla systemów Linux / UNIX (chociaż został przetestowany tylko w systemie OS X) i powinien generować takie same dwukolorowe wyjście dla każdego monitora procesora, który może odróżnić użytkownika od czasu procesora systemowego.

Zasadniczo działa to poprzez wykasowanie siedmiu procesów, z których każdy wybierze 1 sekundę spania, wirowania w trybie użytkownika lub wirowania jądra. Wirowanie w trybie jądra osiąga się przez żądanie dużych globów danych /dev/urandom, co zmusza sterownik /dev/urandomdo zużywania dużej ilości „systemowych” cykli procesora.

ZMIENIONO [07/21]: Znacząco skrócono przez użycie fork()zamiast multiprocessing.Process( /dev/urandomdziała tylko na systemach * NIX, więc nie zmniejsza to przenośności). Zauważ jednak, że program odradza teraz zadania w tle ; być może będziesz musiał killall Python(lub podobnie) pozbyć się procesorów.


Nie mogłem się oprzeć wdrożeniu jeszcze kilku listów. Mam 16 liter i kilka symboli:

~ /._ PIN ANCHO ... ... VY

Kompletny alfabet to „ACDFHILMNOPTUVWY”, z symbolami „._ ~ / \”. Prawdopodobnie jest o wiele więcej znaków, które mogą być reprezentowane.

Całkowicie nieoznaczony kod dla dodatkowych liter:

from time import*
from multiprocessing import*

chars6 = {
'A': ('123456654321',
      '000123321000'),
'C': ('344556666666',
      '321110000000'),
'D': ('666666655443',
      '000000011123'),
'F': ('66666666666666',
      '00002222244444'),
'H': ('666664444466666',
      '000002222200000'),
'I': ('66666',
      '00000'),
'L': ('666662222222',
      '000000000000'),
'M': ('6665544334455666',
      '0004321001234000'),
'N': ('66665544336666',
      '00003322110000'),
'O': ('3445556666555443',
      '3221110000111223'),
'P': ('666666666555',
      '000003333444'),
'T': ('777776666677777',
      '444440000044444'),
'U': ('6666322236666',
      '4211000001124'),
'V': ('66654322345666',
      '33321000012333'),
'W': ('66542466424566',
      '43210133101234'),
'Y': ('66665433456666',
      '44333000033344'),
'_': ('1111111111',
      '0000000000'),
' ': ('000',
      '000'),
'.': ('12221',
      '10001'),
'~': ('44445544334444',
      '11223322112233'),
'/': ('2234566',
      '0012344'),
'\\': ('6654322',
       '4432100'),
}

s = 'ANCHOVY '
A = '000'.join(chars6[t][0] for t in s)
B = '000'.join(chars6[t][1] for t in s)

t=time()
f=open('/dev/urandom')
def F(n):
 while 1:T=int(time()-t)%len(A);[sleep,[].count,lambda x:f.read(4**9)][(n<int(A[T]))+(n<int(B[T]))](1)
for i in range(7):Process(target=F,args=(i,)).start()
F(7)
nneonneo
źródło
34
+1 za nadanie literom większej definicji za pomocą 2 kolorów
DustinDavis
4
I +1 za tworzenie listów na podstawie tabeli
GreenAsJade
1
A może być właściwie renderowane (z otworem) za pomocą 4 wątków. Musiałbym jednak ustawić kilka kolorów monitora CPU.
Ruslan
@ Ruslan: O jakim monitorze procesora myślisz? Mój monitor pokazuje tylko jeden wykres zbiorczy, gdzie 0 <= system <= użytkownik <= 100 w każdym punkcie (co uniemożliwia „dziury” AFAIK).
nneonneo
1
@nneonneo Mam na myśli monitory podobne do twojego. Zobacz to zdjęcie . Tutaj, jeśli zmienimy kolor niebieski na zielony oraz czerwony i fioletowy na biały, otrzymamy ładne „A” z dziurami.
Ruslan
133

C (Intel Core Duo + OS X / Darwin), 248 bajtów

#include <unistd.h>
#include <mach/mach_time.h>
#define M mach_absolute_time()
main(){char*s="JJJIHGFGHIJJJ@BDFHJJJHFDB@JJJJ@JJJJBBBBBBB";uint64_t i,t,y=1;for(;*s;s++){
for(i=40;i;i--){for(t=M+(*s&15)*9090909;t>M;)y*=7;usleep((11-(*s&15))*9091);}}}

Ten kod jest tak samo przenośny jak Wielka Piramida Cheopsa. Przepraszam za to. Wartości zwracane z mach_absolute_time()są zależne od sprzętu, ale na mojej maszynie wartość zwiększa się mniej więcej raz na nanosekundę.

Oto wynik:

Słowo „MAIL” pokazane na moim wykresie historii procesora

Istnieją dwa wykresy, ponieważ procesor ma dwa rdzenie. Ustawiam maksymalne obciążenie procesora na około 90%, ponieważ proces może przełączać się między rdzeniami za każdym razem, gdy dzwonię usleep(). Przy 100% obciążeniu proces jest przykuty do jednego rdzenia, a wyniki są nieczytelne ( patrz na przykład )

piskliwy kostuch
źródło
1
Dobra robota! To wygląda bardzo interesująco. Czy mógłbyś napisać małe wyjaśnienie kodu? :)
duci9y,
1
widzę aparaty ortodontyczne. dlaczego w pętlach for są nawiasy klamrowe? możesz uśpić w drugim bloku ostatniego bloku pętli. myślę, że możesz trochę łatwiej grać w golfa.
bebe
Czy nie można umieścić deklaracji i inicjalizacji uint64_tzmiennych w nagłówku kolejnej forpętli?
Joey,
74
+1: „Ten kod jest tak samo przenośny jak Wielka Piramida Cheopsa”
Uwe Keim
@ Nie, zmienne C muszą być zadeklarowane na początku bloku. umieszczenie go w bloku inicjalizacji for spowoduje błąd. oczywiście dotyczy to tylko <C99
bebe
102

Ruby, 150 znaków

a=(0..15).map{|i|[0.9-3*i*=0.02,i]}
[9,*a[0,11],*(z=a.reverse)[5,11],11,*z,*a,2,11,6,*[0.2]*9].map{|x,y|c=Time.now
1until Time.now-c>x/3
sleep y||x%3}

Jak dotąd nie jest to wcale takie krótkie, ale moim zdaniem wyniki są raczej niezłe, więc pomyślałem, że i tak to opublikuję. Podobnie jak w przypadku większości innych rozwiązań, może być konieczne przypięcie procesu Ruby do określonego rdzenia przez jego prefiks taskset -c $core.

Kod jest prostą kombinacją wirowania / spania przez określony czas, co powinno uczynić go nieco przenośnym. Gładkie gradienty tworzone są poprzez zmianę stosunku czasu wirowania / snu.

MAIL napisany monitor procesora

Obniżenie częstotliwości próbkowania procesora sprawia, że ​​krawędzie wyglądają nieco lepiej:

Niższa częstotliwość próbkowania

Dodając jeszcze kilka liter do alfabetu ( AILMNUVWsą nieco rozpoznawalne), możemy również napisać kilka innych słów:

MAMA, MAW, VILLAIN

Te zdjęcia zostały wygenerowane za pomocą następującego kodu:

def gradient num_samples, direction, base = 0.3, increment = 0.02, scale = 1
    range = [*0..num_samples]

    samples = case direction
        when :up then range.reverse
        when :down then range
        when :updown then range.reverse + range
        when :downup then range + range.reverse
    end

    samples.map{|i|
        i *= increment
        [base - scale * i, i]
    }
end

# letters are defined as a series of pairs of (spin-time, sleep-time)
# with the time in seconds
THIN_A = gradient(15, :updown, 0.2, 0.2/15)
A = gradient(15, :updown)
I = 2,0
L = 1.5,0, [[0.1,0.2]]*9
M = 2,0, gradient(9, :downup), 2,0
N = 1,0, gradient(9, :down), 2,0
U = 1,0, gradient(9, :downup, 0.1, 0.03, 0.1), 1,0
V = 0.5,0, gradient(12, :downup, 0.25, 0.02), 0.5,0
W = 0.5,0, [gradient(12, :downup, 0.25, 0.02)]*2, 0.5,0

[A,I,L,M,N,U,V,W].map{|i|
    # add 2 second pause after each letter
    i + [0,2]
}.flatten.each_slice(2){|x,y|
    # spin, then sleep
    c = Time.now
    1 until Time.now-c > x
    sleep y
}

Słowa, które można zapisać za pomocą zaimplementowanych liter, można znaleźć za pomocą

grep -E '^[aijlmnuvw]+$' /usr/share/dict/words 
Ventero
źródło
4
+1 za rozszerzenie na więcej słów!
Chris Cirefice
Mógłbyś stworzyć słowo „aluminium”.
Oliver Daugherty-Long,
@ OliverDaugherty-Long aluminium *
TuxCrafting
1
@ TùxCräftîñg Aluminium to odmiana pisowni, która ma dodatkową literę i jest najdłuższym słowem, jakie mogę wymyślić.
Oliver Daugherty-Long
48

Python, na Intel Pentium 4 3,0 Ghz, 180 166 145 141 138 138 bajtów

Zadzwoń z taskset -c 0 python cpu_graph_drawer.py.

taskset jest potrzebne, aby ograniczyć proces do korzystania tylko z jednego procesora / rdzenia (w moim przypadku hyperthreading).

from time import*;c=clock
a=[(3,.8),(3,5),(4,5),(1.3,5),(1.3,0)]
a.extend([(.1,.2)]*10)
for x,y in a:
    t=c()
    while c()-t<x:pass
    sleep(y)

Wynik nie jest taki wspaniały. Ten z zestawem zadań -c 1

użytkownik80551
źródło
9
Chciałbym to zobaczyć z monitorem procesora, który nie wygładza krzywych ...
Szabolcs
1
Ja też, ale nie mam ochoty pisać zwariowanego wykresu użycia procesora i gnome-system-monitorto jedyne, co wiem. Masz jakieś alternatywy, które działałyby na LMDE Cinnamon?
user80551,
Włącz „Narysuj procesor jako tabelę warstwową” i ustaw wszystkie kolory na czarne.
Tejas Kale
@TejasKale Linie nadal byłyby zakrzywione.
user80551
FYI: możesz zagrać w golfa kilka znaków, używając a=[...]+[(.1,.2)]*10zamiast .extend.
nneonneo,
46

Java 8, 482 znaków

Każdy znak w ciągu oznacza liczbę wątków, które zostaną wykorzystane. Zdjęcie zrobione na Intel Core i3 (2 rdzenie / 4 wątki).

wynik

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Mail{
public static void main(String[] args) throws InterruptedException{
Thread.sleep(15000);
for(char c:"123432234321000012343210000444000044441111111".toCharArray()){
ExecutorService executorService = Executors.newScheduledThreadPool(4);
for(int i=1;i<c-48;i++)executorService.execute(()->{while(!Thread.interrupted());});
Thread.sleep(1500);
executorService.shutdownNow();
}}}

Edycja : wersja bardziej golfowa (322 znaki), ta sama funkcjonalność:

import java.util.concurrent.*;
class M{
public static void main(String[]a)throws Exception{
for(int c:"123432234321000012343210000444000044441111111".toCharArray()){
ExecutorService s=Executors.newFixedThreadPool(4);
while(c>48){c--;s.execute(()->{while(!Thread.interrupted());});}
Thread.sleep(1500);
s.shutdownNow();
}}}
Tomáš Dvořák
źródło
1
Jest tam mniej niż znak, który został zinterpretowany jako HTML i pomieszał formatowanie.
David Conrad,
@ValekHalfHeart następne dwa wiersze powinny to wyjaśnić. Executor to wątek (asynchroniczny menedżer zadań) wykonujący zadania (tutaj pętle) aż do przerwania. Po utworzeniu wątek główny czeka 1,5 sekundy, a następnie przerywa wszystkie zadania.
PTwr
45
Otwierając Eclipse, mój wykres procesora napisał „Simple Mail Transfer Protocol”.
lolesque
21

C, 78 bajtów

Nigdy nie powiedziałeś, że nie możemy zaakceptować danych wprowadzanych przez użytkownika, więc…

#include <unistd.h>
int main(){int x=0;for(;x<1<<26;++x);read(0,&x,1);main();}

Ten program wczytuje ze standardowego wejścia i za każdym razem, gdy czyta znak, wykonuje nieuzasadnione marnowanie procesora dla pętli, a następnie ponownie wywołuje main. Kontrolujesz ilość czasu wykorzystywanego przez procesor, spamując klawisz Enter z różnymi prędkościami.

Uruchomiłem to na procesorze Intel i3 4130T, który jest dość nowym procesorem. Ale twój przebieg może się różnić, jeśli zużywa mniej lub więcej czasu procesora, niż jest to praktyczne do zaobserwowania, spróbuj grać z wielkością przesunięcia w pętli opóźnienia.

Mój program jest niesamowity, ponieważ:

  • jest przeważnie wieloplatformowy, powinien działać z bardzo małym skrzypkiem na dowolnym * nixie
  • pokonuje pytanie
  • świetna gra końcowa

Po kilku próbach stworzyłem wykres, który wyglądał tak:Wykres procesora

Wug
źródło
Pomaga ograniczyć go do jednego rdzenia procesora za pomocą zestawu zadań, a.l. taskset -c 1 [file]
Wug
2
Nie widzę nic w wymaganiach dotyczących problemu, które yes | [program]
mówiłyby
1
„świetna gra na końcu” sprawiła, że ​​mocno mnie lol. +1
Christoph
1
Ta odpowiedź jest jednak zbyt dobra, niech szlag trafi xD!
Magic Octopus Urn