TS: Chrome, Raspberry-PI, Streaming, Absturz, Zattoo

Hello,

ich habe leider immer noch nicht näher ermittelbare Abstürze meinerRaspberry-Pi 4, wenn ich mittels Chrome das Zattoo-Streaming benutzte. Manchmal läuft es stundenlang störungsfrei, dann stürzt die Raspberry aber auch wieder unvorhersehbar ab.

Wenn ich gleichzeitig ein htop auf einem zusätzichen SSH-Device laufen lasse, zeigt miŕ das immer den Absturz in einem einzigen Thread (von vier laufenden) Chrome-Thread an. Leider steht dann das gesamte System.

Glück Auf
Tom vom Berg

--
Es gibt soviel Sonne, nutzen wir sie.
www.Solar-Harz.de
S☼nnige Grüße aus dem Oberharz
  1. Hm. Raspi4 stürzt also ab.

    1. Wie sieht es denn mit der Temperatur aus?
    2. Und mit Speicher(RAM)?
    3. Verwendest Du eine Speicherkarte, USB-Stick oder eine SSD?
    4. Gibt es zram, swap?
    5. Verwendest Du ramlog (log2ram)?
    6. Wie wird der Raspi gekühlt?
    7. Ist er getunt?
    8. Sagen die Logs etwas? (sylog, kern.log, dmesg)

    Wenn ich gleichzeitig ein htop auf einem zusätzlichen SSH-Device laufen lasse, zeigt miŕ das immer dann Absturz in einem einzigen Thread (von vier laufenden) an. Leider steht dann das gesamte System.

    Du meinst mit „das gesamte System“ die grafische Oberfläche? Der SSH-Server und htop scheinen ja Deiner Äußerung nach noch zu laufen…

    Nie vergessen:

    1. Hello,

      Hm. Raspi4 stürzt also ab.

      1. Wie sieht es denn mit der Temperatur aus?

      Alles m Rahmen

      1. Und mit Speicher(RAM)?

      Laut htop maximal 50% genutzt

      1. Verwendest Du eine Speicherkarte, USB-Stick oder eine SSD?

      Speicherkarte

      1. Gibt es zram, swap?

      SWAP ja

      1. Verwendest Du ramlog (log2ram)?

      nö, nicht dass ich wüsste

      1. Wie wird der Raspi gekühlt?

      Dickes Alu-Gehäuse. Die Temperaturabfrage des Kernels ist auch nicht bedenklich.

      1. Ist er getunt?

      Womit? Ich habe keine Parameter verstellt.

      1. Sagen die Logs etwas? (sylog, kern.log, dmesg)

      Muss ich nochmal prüfen. Das könnte noch Erkenntnisse bringen.

      Das Problem kam auch erst mit der Umstellung der Streaming-Kanäle auf HD auf. Am Anfang gab es das nur bei Zattoo-Alpha.

      Da war die Lastanzeige (htop) dann kontinuierlich im Limit.

      Nach einem Upgrade wurde es etwas besser, nach weiteren sogar erheblich. Die Last sank von über 4 (theoretisches Maximum) auf ca. 1,9 bis 2,5.

      Aber manche Tage stürzt das Ding dann trotzdem noch ins Nirwana und einer der Threads ist dann über alle Limits.

      Glück Auf
      Tom vom Berg

      --
      Es gibt soviel Sonne, nutzen wir sie.
      www.Solar-Harz.de
      S☼nnige Grüße aus dem Oberharz
  2. Starte den „Chrome“ mal manuell im Terminal und logge die Ausgaben.

    • Den Befehl hierzu kannst Du via des, zum Bearbeiten des Startmenüs bestimmten Programms Deiner Installation ermitteln.

    Bei mir (sic: bei MIR!) ist das /usr/bin/chromium-browser.

    Starte den dann wie folgt:

    $DeinStartBefehl 1> ~/chromium.log 2> ~/chromium.log
    

    und zeige uns nach dem Absturz die letzten (ungefähr) 20 Zeilen:

    tail -n20 ~/chromium.log
    

    (Die kannst Du mit tail -f ~/chromium.log auch in einer ssh-Sitzung holen...)

    1. Hallo,

      $DeinStartBefehl 1> ~/chromium.log 2> ~/chromium.log
      

      kann das gutgehen? Mit zwei Handles konkurrierend in dieselbe Logdatei schreiben? Ich würde sicherheitshalber zwei verschiedene nehmen.

      Einen schönen Tag noch
       Martin

      --
      "Malen nach Zahlen" sagten wir im Matheunterricht, wenn es bei der Kurvendiskussion hieß: Zeichnen Sie den Graphen der Funktion ...
      1. kann das gutgehen?

        Du hast Recht. Tut es nicht.

        Korrektur des Startbefehls:

        $DeinStartBefehl 1> ~/chromium.log 2> ~/chromium.err
        

        Korrektur des „Fernsehens“:

        tail -n20 ~/chromium.log ~/chromium.err
        

        Getestet mit:

        #/usr/bin/bash
        
        echo "1: Teste Fehlerkanal" 1>&2;
        echo "2: Teste Standardoutput";
         
        echo "3: Teste Fehlerkanal" 1>&2;
        echo "4: Teste Standardoutput";
        

        und

        ./test.sh 1> test.log 2> test.err; cat test.log test.err
        
        1. Hello,

          kann das gutgehen?

          Du hast Recht. Tut es nicht.

          Muss es aber!

          Wenn da nicht proprietär mit dem Dateizeiger herumgewerkelt wird, ist sogar bei Windows sichergstellt, dass der Append-Mode beim Beschreiben von Logdateien vom OS kontrolliert wird und Schreibzugriffe auf dieselbe Datei streng serialisiert werden.

          Diese "Fossil-Funktion" ist bis heute am Leben erhalten worden, aus gutem Grund!

          Glück Auf
          Tom vom Berg

          --
          Es gibt soviel Sonne, nutzen wir sie.
          www.Solar-Harz.de
          S☼nnige Grüße aus dem Oberharz
          1. Hello,

            kann das gutgehen?

            Du hast Recht. Tut es nicht.

            Muss es aber!

            Tut es aber nicht. Hatte ich, wie gezeigt, getestet. Da ist der Wunsch irrelevant.

            Willst Du alle Ausgaben in einem Logfile, welches bei einem neuen Start auch neu geschrieben wird,dann bleibt Dir (wie Robert auch schon schrieb):

            $DeinStartBefehl 2> $DeinLogFile 1>&2
            

            Hierbei sorgt das nachgestellte (hinten stehende!) 1>&2 dafür, dass die Standardausgabe zur Fehlerkonsole umgeleitet wird und das 2> $DeinLogFile, dass die Fehlerkonsole sodann in eine Datei umgeleitet oder zu einem Gerät geschickt wird.

            Willst Du alle Ausgaben an ein Logfile anhängen, dann möge

            $DeinStartBefehl 2>> $DeinLogFile 1>&2
            

            genügen.

            Tipp:

            Ich hab nachgesehen, was Du wohl mit „streamen“ meinst. Das ist wohl das Streamen zu solchen Chromcast-Dingern. Das verursacht durchaus eine hohe Prozessor-Last, die gleichberechtigt ist und die vergleichbar geringe Rechenkapazität eines Raspi „stark bindet“.

            Daraus ergibt sich folgender Ansatz:

            Ich starte den chromium-browser wie folgt:

            #!/bin/sh
            if [ -f /usr/bin/chromium ]; then
            	p="/usr/bin/chromium";
            elif [ -f /usr/bin/chromium-browser ]; then
            	p="/usr/bin/chromium-browser";
            fi
            wmctrl -R 'chromium' || $p --start-maximized $* 
            exit
            

            (Das Programm wmctrl kannst Du mit sudo apt install wmctrl nachinstallieren.)

            Das Skript prüft zunächst, ob chromium oder chromium-browser installiert ist.

            Dann schaut es nach, ob sich ein Fenster mit 'chromium' im Titel wieder herstellen (in den Vordergrund holen) lässt. Wenn nicht wird der Browser gestartet. Das mag nicht perfekt sein, weil es auch ein Fenster mit dem Titel "chromium-browser.sh - /home/foo/bin/ - geany" in den Vordergrund holt, genügt aber in meinem Alltag - das verhindert bei mir, dass ich notlos und Ressourcen verschwendend etliche Chromium-Fenster aufmache, ich habe alle Vorkommen im Menü oder sonstigen Icons (Schnellstart, Desktop) angepasst... und verfahre mit einem ganzen Rudel anderer Programme genau so.)

            Was Dir das bringt:

            Du kannst versuchen, die Zeile

            wmctrl -R 'chromium' || $p --start-maximized $* 
            

            anzupassen:

            wmctrl -R 'chromium' || nice -10 $p --start-maximized $* 
            

            Danach startet der chromium als ziemlich freundlicher Mitbürger - auch dessen Kinder sind plötzlich auffallend nett und lassen im Fall des Falles andere Prozesse vor. Ich vermute, dann bleibt Dein Desktop steuerbar - auch wenn der Prozess, der gerade das Fenster des Chromium als Video in die Gegend schickt, stark ausgelastet ist.

      2. Hello Martin,

        $DeinStartBefehl 1> ~/chromium.log 2> ~/chromium.log
        

        kann das gutgehen? Mit zwei Handles konkurrierend in dieselbe Logdatei schreiben? Ich würde sicherheitshalber zwei verschiedene nehmen.

        In Logdateien schreiben findet üblicherweise im Append-Mode statt und da kümmert sich das Betriebssystem selber um Kollisionsfreiheit. Append-Schreiboperationen (auch über mehrere Threads hinweg) auf dieselbe Datei werden vom OS serialisiert.

        Und welch Wunder: das funktioniert sogar bei WINDoofs ;-P

        Glück Auf
        Tom vom Berg

        --
        Es gibt soviel Sonne, nutzen wir sie.
        www.Solar-Harz.de
        S☼nnige Grüße aus dem Oberharz
        1. n'Abend Tom,

          $DeinStartBefehl 1> ~/chromium.log 2> ~/chromium.log
          

          kann das gutgehen? Mit zwei Handles konkurrierend in dieselbe Logdatei schreiben? Ich würde sicherheitshalber zwei verschiedene nehmen.

          In Logdateien schreiben findet üblicherweise im Append-Mode statt

          ja, das mag wohl sein. Hier haben wir aber den Fall, dass erst eine Datei zum Schreiben geöffnet wird (nicht append, sondern create!) und das stdout-Handle dann auf diese Datei gelenkt wird; dann wird dieselbe Datei mit einem zweiten Handle nochmal neu erzeugt und diesmal stderr auf dieses neue Handle gelenkt.[1] Das ist wtwas anderes als das koordinierte Schreiben mehrerer Prozesse in eine gemeinsame Log-Datei, das ja in der Regel über einen weiteren Prozess koordiniert wird, der die Schreibzugriffe serialisiert und geordnet umsetzt.

          und da kümmert sich das Betriebssystem selber um Kollisionsfreiheit. Append-Schreiboperationen (auch über mehrere Threads hinweg) auf dieselbe Datei werden vom OS serialisiert.

          Ja. Aber dann müsste man mindestens das stderr-Handle auch im Append-Modus umleiten, also mit 2>>, vielleicht sogar beide, damit's nicht knallt.

          Und welch Wunder: das funktioniert sogar bei WINDoofs ;-P

          Das ist nun wirklich erstaunlich.

          Einen schönen Tag noch
           Martin

          --
          "Malen nach Zahlen" sagten wir im Matheunterricht, wenn es bei der Kurvendiskussion hieß: Zeichnen Sie den Graphen der Funktion ...

          1. Das zweite Öffnen derselben Datei im create-Modus müsste schon fehlschlagen (File Locking). ↩︎

      3. Moin,

        $DeinStartBefehl 1> ~/chromium.log 2> ~/chromium.log
        

        kann das gutgehen? Mit zwei Handles konkurrierend in dieselbe Logdatei schreiben? Ich würde sicherheitshalber zwei verschiedene nehmen.

        Ich kenne daher die Variante

        $DeinStartBefehl > ~/chromium.log 2>&1
        

        also logge jede Ausgabe in die Datei und leite die Fehlerausgabe nach stdout um.

        Viele Grüße
        Robert

    2. Mir fällt es gerade wie Schuppen von den Augen... Streamen erzeugt womöglich eine ziemlich hohe Last, welche den Prozessor vollständig beschäftigt. Der vermeintliche „Absturz“ könnte also eine „Schwester“ des bei mir aufgefallenen Problems mit der Auslastung sein.

      Dann wäre das folgende eine mögliche Lösung:

      Starte den „Chrome“ mal manuell im Terminal und logge die Ausgaben.

      Den Befehl hierzu kannst Du via des, zum Bearbeiten des Startmenüs bestimmten Programms Deiner Installation ermitteln.

      • Bei mir (sic: bei MIR!) ist das /usr/bin/chromium-browser.

      (Bis hier her entspricht das Antwort Nr. 2)

      Starte den Chrome dann wie folgt:

      nice -n 19 $DeinStartBefehl
      
      • Ändere den Befehl im Startmenü ab.
      1. #! /usr/bin/python3
        
        
        from pathlib import Path
        import math
        
        class cpufreq:
        
        	def __init__( self ):
        		self._governor      = ''
        		self._minfreq       = ''
        		self._curfreq       = ''
        		self._maxfreq       = ''
        		self._calcstates    = ''
        		self._sysruntime    = ''
        		self._cpuTimefactor = 100
        		self._hmFactor      = 1000000
        		self._hmString      = 'GHz'
        		self._tempFile      ='/sys/devices/virtual/thermal/thermal_zone0/temp'
        		self._tempFaktor    = 0.001
        		self._tempFormat    = '′C'
        		if ( Path( '/sys/devices/system/cpu/cpu0/cpufreq/' ).is_dir() ) :
        			self._path = '/sys/devices/system/cpu/cpu0/cpufreq/'
        		elif ( Path( '/sys/devices/system/cpu/cpufreq/' ).is_dir() ):
        			self._path = '/sys/devices/system/cpu/cpufreq/'
        		self.read_from_system( );
        
        	def read_the_line( self, fileName ):
        		f = open( fileName, 'r' )
        		l = f.read().strip()
        		f.close()
        		return l
        
        	def human_readble( self, z ):
        		z = z / self.hmFactor
        		return '%0.3f %s'%( z, self._hmString )
        
        	def Seconds2Human( self, s:int, daystring = 'd' ):
        		s = int(s)
        		# Days
        		if ( s > 86400 ):
        			d = math.floor( s / 86400 )
        			s = s - d * 86400
        		else:
        			d = 0
        		
        		# Houres
        		if ( s > 3600 ):
        			h = math.floor( s / 3600 )
        			s = s - h * 3600
        		else:
        			h = 0
        				
        		# Minutes
        		if ( s > 60 ):
        			m = math.floor( s / 60 )
        			s = s - m * 60
        		else:
        			m = 0
        		
        		return '%d%s %02d:%02d:%02d'%( d, daystring, h, m, s )
        
        	def read_from_system( self ):
        		if ( Path( self._path + 'scaling_governor' ).exists() ):
        			self._governor   =  self.read_the_line( self._path + 'scaling_governor' )
        			self._minfreq    =  self.read_the_line( self._path + 'scaling_min_freq' )
        			self._curfreq    =  self.read_the_line( self._path + 'scaling_cur_freq' )
        			self._maxfreq    =  self.read_the_line( self._path + 'scaling_max_freq' )
        		elif( Path( self._path + 'cpuinfo_min_freq' ).exists() ):
        			self._governor   = false
        			self._minfreq    = self.read_the_line( self._path + 'cpuinfo_min_freq' )
        			self._maxfreq    = self.read_the_line( self._path + 'cpuinfo_max_freq' )
        
        			if ( Path( self._path + 'cpuinfo_curr_freq' ).exists() ):
        				self.curfreq = self.read_the_line( self._path + 'cpuinfo_cur_freq' )
        
        			elif ( self._maxfreq == self._minfreq ):
        				self._curfreq = self._minfreq
        
        			else:
        				self._curfreq = 0
        		else:
        			self._governor = false
        			self._minfreq  = 0
        			self._curfreq  = 0
        			self._maxfreq  = self.read_the_line( self._path + 'cpuinfo_max_freq' )		
        
        		if ( Path( self._path + 'stats/time_in_state' ).exists() ):
        			# self._calcstates = self.read_the_line( self._path + 'stats/time_in_state' )
        			self._calcstates = self.readTimestates()
        
        		else:
        			self._calcstates = false
        
        	def human_readble ( self, z ):
        		z = int(z) / self._hmFactor
        		return '%0.3f %s' % ( z, self._hmString )
        
        	def getFreq ( self, v, hm ):
        		if ( hm ):
        			return self.human_readble( v )
        		else:
        			return v
        
        	def readTimestates( self ):
        		f = open( self._path + 'stats/time_in_state' , 'r' )
        		lines = f.readlines()
        		f.close
        		summe = 0
        		arr = {}
        		for line in lines:
        			line = line.strip()
        			if ( line ):
        				f, t =  line.split(' ')
        				t = math.floor( int(t) / self._cpuTimefactor )
        				d = {};
        				if ( t != 0 ):
        					summe += t
        					f = self.human_readble( f )
        					d['t_abs'] = t
        					d['t_hum'] = self.Seconds2Human( t )
        					arr[f] = d
        
        		self._sysruntime = summe;
        				
        		for f in arr.keys():
        			arr[f]['t_rel'] = '%1.4f'%(round( arr[f]['t_abs'] / summe, 4 ) )
        			arr[f]['t_100'] = '%5.1f%%' %( round( arr[f]['t_abs'] / summe * 100 , 1 ) )
        		return arr
        
        	def getMinFreq( self, hm = False ):
        		 return self.getFreq ( self._minfreq, hm )
        
        	def getCurFreq( self, hm = False ):
        		 return self.getFreq ( self._curfreq, hm )
        
        	def getMaxFreq( self, hm = False ):
        		 return self.getFreq ( self._maxfreq, hm );
        
        	def getSysRunTime( self, hm = False ):
        		if ( hm ):
        			return self.Seconds2Human( self._sysruntime );
        		else:
        			return self._sysruntime;		
        
        	def getCpuTemp ( self, hm = False ):
        		t = float( self.read_the_line( self._tempFile ).strip() )
        		t = t * self._tempFaktor;
        		if ( hm ):
        			return '%4.1f%s'%(round( t, 1 ), self._tempFormat);
        		else:
        			return t;
        	
        	def getCalcstates ( self ):
        		return  self._calcstates;
        	
        	def getGovernor ( self ):
        		return self._governor;
        
        
           
            
        ### main ###
        
        import os
        if not os.environ.get('SHELL'):
            
            print ( 'Content-Type: text/plain; charset=utf-8' )
            print ( 'Refresh: 1' )
            print ()
        
        cf = cpufreq()
        CurFreq = cf.getCurFreq( True )
        
        print ('Governor:              ' , cf.getGovernor() )
        print ('Geringste Frequenz:    ' , cf.getMinFreq( True ) )
        
        print ('Gegenwärtige Frequenz: ' , CurFreq , ' <' )
        print ('Maximale Frequenz:     ' , cf.getMaxFreq( True ) )
        print ('System läuft seit:     ' , cf.getSysRunTime( True ) )
        
        a = cf.getCalcstates()
        if ( a ):
        	
        	print ( 'Zeitliche Frequenznutzung:' )
        	for freq in a.keys() :
        		if ( freq == CurFreq ):
        			LE = ' <'
        		else:
        			LE = ''
        		print ( freq + ': ' , a[freq]['t_100'] , LE )
        
        print ('Temperatur:' , cf.getCpuTemp( True ) )
        print()
        
        

        als cpufreq.py speichern, chmod 755 ...

        in der ssh-shell mit watch -n1 -t cpufreq.py starten und überwachen.

        Sieht dann ETWA so aus:

        Governor:               ondemand
        Geringste Frequenz:     1.500 GHz
        Gegenwärtige Frequenz:  2.300 GHz  <
        Maximale Frequenz:      2.300 GHz
        System läuft seit:      1d 17:48:23
        Zeitliche Frequenznutzung:
        0.600 GHz:    0.0% 
        0.700 GHz:    0.0% 
        0.800 GHz:    0.0% 
        0.900 GHz:    0.0% 
        1.500 GHz:   18.3% 
        1.800 GHz:    0.0% 
        2.300 GHz:   81.7%  <
        Temperatur: 57.5′C
        

        Damit kannst Du nachsehen, ob der Raspi eventuell zu heiss wird und welche Frequenzen er fährt. (Meiner ist „schwer getunt“.)