Forum: Mikrocontroller und Digitale Elektronik ReadFile(.) - Zugriff auf die RS232 über Windows-API. Performance?


von Alexander I. (daedalus)


Lesenswert?

Hallo,

ich greife mit Hilfe eines Workerthreads auf die serielle Schnittstelle 
zu. Dabei erfolgt die Kommunikation mit dem Hauptprogramm über jeweils 
eine separate queue<char>. Der Einfachheit halber habe ich mit ReadFile 
jedes Byte separat abgeholt und in die Queue eingefügt. Funktioniert 
auch, aber ich hab das Gefühl, die Performance ist da ganz schön 
bescheiden. Leider kann ich an keinem Pin wackeln und so am Oszi 
nachmessen, was da Phase ist.

Vielleicht kann mir jemand von euch eine Hausnummer nennen, wie lange so 
ein ReadFile-Aufruf durchschnittlich dauert und ob es besserer Stil ist, 
immer alle Bytes aus dem Rx-Puffer mit einem Aufruf zu lesen?

von Volker Z. (vza)


Lesenswert?

Hallo
Dein 'Pin' ist der Performance-Monitor.
Deine Übertragung dauert : [Zeit] = [Anzahl-Bytes]/[baud]*10
Die Zehn komt von 8N1.

Sicherlich ist es Performanter ganze Blöcke zu lesen.
Aber du wirst es weder merken noch messen können.
Ich habe einen blockierenden Aufruf verwendet. Er kehrt bei mir erst 
zurück wenn entweder :
 - Bestimmte Anzahl Bytes angekommen sind.  oder
 - Ein bestimmtes Zeichen angekommen ist.   oder
 - Ein Timeout aufgetreten ist.

viel Spass beim Rechnen!

von Alexander I. (daedalus)


Lesenswert?

Hallo, deine Rechnung ist soweit schon klar. Ich habe aber die 
Befürchtung, dass der Löwenanteil vom Windows selbst verschlungen wird 
und ontop auf die reine Übertragungszeit kommt. Da hätte ich halt gerne 
eine Hausnummer wie lange so ein ReadFile(1 Datenbyte) im Durchschnitt 
dauert.

Vielen Dank soweit.

von Karl H. (kbuchegg)


Lesenswert?

Nochmal.
Es ist ziemlich egal, was du oder Windows in deinem Programm machst. 
Solange du nicht mutwillig Unmengen an Rechenzeit verbrutzelst 
natürlich. Dein zeitbestimmender Flaschenhals ist die eigentliche 
Übertragung an der seriellen Schnittstelle. Im Vergleich zu dem, was 
sich an dieser Schnittstelle abspielt, ist alles andere völlig 
unwichtig. Und wenn du zwischen dem Senden zweier Bytes 3 Millionen 
quadratische Gleichungen löst, wirst du den Unterschied nicht merken 
oder messen können.
Oder anders ausgedrückt: Ob die Küche 5 oder 10 Sekunden zur 
Bereitstellung eines Menütellers benötigt ist völlig uninteressant, wenn 
der Kellner 2 Minuten braucht um es zum Gast zu bringen. In dieser Zeit 
stellt die Küche den nächsten Teller auf jeden Fall her, egal ob sie 5 
oder 10 Sekunden dafür braucht.

von Volker Z. (vza)


Lesenswert?

1
  LONGLONG  freq,start,stop,diff;
2
  double  time;
3
4
  HANDLE hProg = GetCurrentProcess();
5
  assert(hProg);
6
  assert(SetPriorityClass(hProg,REALTIME_PRIORITY_CLASS));
7
8
  hProg = GetCurrentThread();
9
  assert(hProg);
10
   assert(SetThreadPriority(hProg,THREAD_PRIORITY_HIGHEST));
11
12
  if(!QueryPerformanceFrequency((LARGE_INTEGER*)&freq))
13
  {
14
    printf("no PerformanceCounter,\n");
15
    exit (-2);
16
  }
17
  printf("freq is %I64u per sec.\n",freq);
18
19
  for(ByteData=0;ByteData<101;ByteData++)
20
  {
21
//    set = ByteData%6;
22
    set = ByteData;
23
    QueryPerformanceCounter((LARGE_INTEGER*)&start);
24
    Sleep(set);
25
    QueryPerformanceCounter((LARGE_INTEGER*)&stop);
26
    diff = stop - start;
27
    printf(" % 4u : ",set);
28
//    printf(" %I64u %I64u  %I64u ",start,stop,diff);
29
    time = diff;
30
    time /= freq;
31
//    printf(" %I64u %f ",diff,time);
32
    time *= 1000.0;
33
    printf(" %.3f ms",time);
34
    printf("\n");
35
  }
36
   fprintf(stderr,"\nHit any key.\n\n\n");
37
   getchar();
38
  exit(-1);

ich habe mal die Function sleep ausgemessen.
Ist das was du suchst?

von Alexander I. (daedalus)


Lesenswert?

Hallo,

ich habe die Ursache für den schleichenden Workerthread gefunden. Die 
Fehlerursache war in der falschen bzw. nicht durchgeführten 
Konfiguration der Timeoutparameter begründet. Diese habe ich jetzt auf
1
COMMTIMEOUTS ctmo;
2
ctmo.ReadIntervalTimeout = MAXDWORD;
3
ctmo.ReadTotalTimeoutMultiplier = 0;
4
ctmo.ReadTotalTimeoutConstant = 0;
5
SetCommTimeouts(Device, &ctmo);

gestellt, damit ReadFile nicht im Timeout wartet (sofern keine Daten 
mehr kommen), sondern sofort zurückkehrt. Zusätzlich hab ich noch einen 
Fehler in meinen Synchronisations-Events gefunden und übertrage jetzt 
nicht jedes Byte einzeln sondern bis zu 256 pro Threaddurchlauf.

Das ganze flutscht jetzt um Größenordnungen besser. Die Abarbeitung 
eines "Kommunikationsablaufs" hat vorher gut 8-10 Sekunden gedauert. 
Nach der Überarbeitung <1 Sekunde.

Zwar war das hier nicht direkt die Problemlösung, hat mich jedoch auf 
den richtigen Lösungsweg gebracht. Vielen Dank soweit.

von Peter (Gast)


Lesenswert?

Warum soll das ReadFile denn zurückkommen wenn keine Daten empfangen 
wurde? Das ist ja sinn und zweck der Sache wenn du schon ein Extra 
Thread hast.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.