Announcement

Collapse
No announcement yet.

Unmanaged Image - wie mache ich das richtig?

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Unmanaged Image - wie mache ich das richtig?

    Hallo,
    ich wollte eine Klasse schreiben, die die bytes eines Grauwertbildes speichert, mit dem Zweck, manche Bildoperationen zu beschleunigen.
    Die Klasse sieht so aus:
    Code:
    public class GrayImage
    {
      public int Width{get;set;}
      public int Height{get;set;}
    
      private unsafe byte* m_pData;
    
      public GrayImage(int width, int height, byte bValue)
      {
        this.Width = width;
        this.Height = height;
    
        int nLength = this.Width * this.Height;
    
        unsafe 
        {
          byte* pData = stackalloc byte[nLength];
          this.m_pData	 = pData;
        }
    
        for (int i = 0; i < nLength; i++)
        {
            this.m_pData[i]	= bValue;
        }
      }
    }
    Dieser Code kompiliert und wenn ich am Ende des Konstruktors die Memory gucke, so sehe ich, dass alle Werte in m_pData auf den Wert bValue gesetzt sind. Aber wenn ich den Konstruktor verlasse, z.B. nach dem Aufruf GrayImage gi = new GrayImage(8, 8, 64); muss ich sehen, dass der gesetzte Wert vergessen ist, und im Byte-Array von gi zufällige Werte stehen: die Daten wurden verloren.

    Ich kapiere ehrlich gesagt nicht, was ich hier falsch mache (und offensichtlich ist es so). Mit dem unsafe-Kapitel in C# habe ich irgendwie nicht so viel Erfahrung und Gefühl.
    Dank für alle Tipps - A.K.

  • #2
    pData ist eine nur im Konstruktor gültige Adresse. Warum nicht gleich der Membervariablen zuweisen
    Christian

    Comment


    • #3
      Habe ich natürlich auch versucht:
      Code:
      this.m_pData = stackalloc byte[nLength];
      das liefert aber die Fehlermeldung:
      Error 1 Invalid expression term 'stackalloc' L:\TestUnsafeGrayImage\GrayImage.cs
      wobei wenn ich das in
      Code:
      byte* pData= stackalloc byte[nLength];
      this.m_pData= pData;
      umwandle, gibt es keinen Fehler. Ich verstehe auch nicht, warum.
      Gruß, A.K.

      Comment


      • #4
        Hast Du es denn schon auf dem .Net Weg versucht und gesehen dass es tatsächlich zu langsam ist?

        Comment


        • #5
          Genau chronometriert habe ich noch nicht, habe aber vor, es bald zu machen. Gefühlsmäßig ist es aber so, dass meine alten C++ Klassen auf diesem Bereich um eine Größenordnung schneller waren. Du hast aber Recht, bevor man etwas behauptet, sollte man eine begründete Untersuchung machen - ich mache das und teile mit, was rauskommt. Trotzdem interessiert mich, wie man diese Sachen korrekt in C# macht. Das Googln hat nicht viel gebracht, daher ist meine Hoffnung, dass jemand im Forum sich gut damit auskennt.
          Zuletzt editiert von Alex.Konnen; 23.06.2014, 10:39.

          Comment


          • #6
            Zitat aus der Doku zu stackalloc

            The lifetime of the memory block is limited to the lifetime of the method that defines it.
            Ich habe es nicht ausprobiert aber nach meinem Verständnis sollte der Speicherblock nicht mal den unsafe Block überleben. Es wäre eher unsicher wenn man Dinge die unsafe sind aus einem unsafe Block herausholen könnte.

            Comment


            • #7
              Korrekt! Ich versuche gedankenlos auf dem Stack zu allozieren, wobei ich eigentlich den Heap meine...
              Anscheinend gibt es aber auch die Möglichkeit, mit dem Heap umzugehen: z.B. habe ich zu diesem Thema den Link http://msdn.microsoft.com/en-us/libr...=vs.71%29.aspx gefunden.

              Comment


              • #8
                Ich habe gestern versprochen, einen Performance-Vergleich zwischen C++ und C# zu machen. Jetzt habe ich die Performanz einer C++ und einer C# Klasse verglichen. Die beiden speichern die Größe des Bildes und die Bytes, wobei in C++ für jede Zeile ein BYTE-Pointer angelegt wird, dessen Länge die Breite des Bildes ist, und ein Pointer auf den Pointer-Array:
                Code:
                BYTE** m_ppData;
                ...
                m_ppData = new BYTE*[this->Height];
                
                for (int r = 0; r < this->Height; r++)
                {
                  this->m_ppData[r] = new byte[this->Width];
                }
                Die C#-Klasse speichert ebenfalls die Breite und die Höhe des Bildes, und die Bytes als "jagged"-Array:
                Code:
                private byte[][] m_xData;
                this.m_xData    = new byte[this.Height][];
                
                for (int r = 0; r < this.Height; r++)
                {
                  this.m_xData[r]    = new byte[this.Width];
                }
                Diese Struktur der Byte-Arrays leistet meinem Gefühl nach die geringste Zugriffszeit.

                Um die Performanz zu vergleichen, habe ich die Averaging-Operation laufen lassen, in der ein neues Bild erzeugt wird, dessen Grauwerte als Mittel über ein quadratisches Fenster des Quellbildes berechnet werden.
                Die Konsolenprogramme wurden für C++ und C# mit VS 2013 (.NET 4.5.1, Release) erzeugt. Die Maschine ist ein Asus-Laptop mit Pentium Dual-Core 2.00 GHz, 2.00 GB RAM, Windows 7 32-Bit.

                Anbei die Ergebnisse:

                Performance Comparison C++ vs C#- Averaging.jpg

                Für relativ kleine Fenstergrößen beträgt der Performanzverlust bei C# also 150 .. 200% (das C#-Programm ist mit Faktor 1.5 .. 2.0 langsamer), bei größeren Breiten des Mittlungsfensters verschlechtert sich die relative Performanz sogar bis zum Faktor 3. So sieht es also aus mit dem pur gemanagtem Code. Es wäre interessant, ob noch jemand ähnliche Vergleiche gemacht hat und was sie gebracht haben. Danke für die Aufmerksamkeit, A.K.

                P.S. Da der Graph viel zu schlecht zu sehen ist, noch eine Tabelle dazu - hoffentlich klar (Durchschnittszeiten über 5..6 Proben in ms).

                W=H=128 W=H=480
                Aver. Size C++ C# C++ C#
                3 0 1 5.45 10.8
                5 0.75 2 13.25 21.2
                7 1.55 3 19.5 38
                9 2.3 4 26.55 59.4
                11 2.3 6 32.75 85.2
                13 3.1 8 43.7 101.8
                15 3.1 9 56.15 156.2
                Zuletzt editiert von Alex.Konnen; 24.06.2014, 08:43.

                Comment


                • #9
                  Ist der c# Code weiterhin unsafe?

                  Comment


                  • #10
                    Nein, der Code, den ich für den Vergleich genommen habe, war auch sonst komplett Safe.

                    BTW: es wäre interessant, es auch mit der Performanz an einer Linux-Maschine zu vergleichen. Ich kann mir nämlich vorstellen, dass der Mono-Code deutlich schneller ausgeführt wird als der gleiche Code an einem Windows-Rechner.
                    Zuletzt editiert von Alex.Konnen; 24.06.2014, 11:07.

                    Comment


                    • #11
                      Ich frage weil ein unsafe Code Block auch Einfluss hat auf die Codegenerierung (Boundschecking etc.) und das dann wiederum eventuell Einfluss auf die Performance hat und nicht nur auf die ~Sicherheit~. Unter 2.0 war das mal ein Faktor denn man in bestimmten Fällen berücksichtigen sollte. Ob das im aktuellen Framework noch einen Unterschied macht weiß ich allerdings nicht.

                      Edit:

                      Anscheinend gibt es aber auch die Möglichkeit, mit dem Heap umzugehen: z.B. habe ich zu diesem Thema den Link http://msdn.microsoft.com/en-us/libr...=vs.71%29.aspx gefunden.
                      Der UnmanagedMemoryAccessor kaspelt das vermutlich entsprechend bereits.

                      Comment


                      • #12
                        Von .NET 2.0 habe ich wie gut wie keine Ahnung, bin mit 3.0 eingestiegen. Den Vergleich habe ich mit VS 2013 (also 4.5.1) durchgeführt.
                        Danke für den Hinweis, Ralf! Könnte interessant sein für meine Zwecke
                        Zuletzt editiert von Alex.Konnen; 24.06.2014, 11:41.

                        Comment

                        Working...
                        X