• Das Erstellen neuer Accounts wurde ausgesetzt. Bei berechtigtem Interesse bitte Kontaktaufnahme über die üblichen Wege. Beste Grüße der Admin

Prototyping verbraucht 100% CPU load in NodeJs

xorg1990

New member
Hallo, ich steh mal wieder vor einen Rätsel.

Sicherlich kann sich der eine oder andere noch an den "Hilbert Trafo Thread" erinnern. Diese ganze Sache habe ich nun nach nodejs gebracht.

Das Problem der Prozess verbraucht 100% CPU Load in nodejs.

Ich habe 2 Dateien, in der main.js habe ich eine Methode die von Gstreamer Daten empfängt und in Downmixer.js habe einen Methode pushSample die, die Samples verarbeitet.

main.js
Code:
GstreamerPipe.Receive(function(data){
	var j = 0;
	while(j!=data.length){
		j++;
	downmix.pushSample(data[j]);
	//console.log(downmix.getMix());
	}
});

Downmixer.js
Code:
function Downmixer(VFO_Freq, Samplerate){
	this.FILTER_LEN = 100; //FIR Hilbert length 
	
	this.VFO_Sine =  require('../node_modules/audiolib').Oscillator(Samplerate, VFO_Freq);
	this.VFO_Cosine = require('../node_modules/audiolib').Oscillator(Samplerate, VFO_Freq);
	this.VFO_Sine.waveShape = 'sine';
	this.VFO_Cosine.waveShape = 'cosine';
	this.queue_ptr = 0;
	this.iDelayIndex = 0;
	
	this.maxi = 0.001;
	this.maxq = 0.001;
	this.DelayQueue = new Float32Array(this.FILTER_LEN);
	this.BufferQueue = new Float32Array(this.FILTER_LEN);
	this.calcCoeff();
}

Downmixer.prototype.calcCoeff = function(){
	var HILBERT_ARRAY = new Float64Array(this.FILTER_LEN);
	
	HILBERT_ARRAY[this.FILTER_LEN] = 0;
     for (var jj = 0; jj <= this.FILTER_LEN / 2; jj++) {
         var coeff = jj & 1 ? 2.0 / ((this.FILTER_LEN / 2 - jj) * Math.PI) : 0.0; //<- Implementierung W Kiefer
         //var coeff = jj&1 ? 2.0/(jj*Math.PI) : 0.0;//<- Implementierung Wolf Büscher
         //var coeff = 1/((jj-FILTER_LEN/2)-0.5)/Math.PI; //<- Eigene Implementierung  der Koeffizienten
         HILBERT_ARRAY[jj] = coeff;
         HILBERT_ARRAY[this.FILTER_LEN - jj] = -coeff;
     }
	this.coeffs = HILBERT_ARRAY;	
};


Downmixer.prototype.pushSample = function(s){
		//generate the sine samples from audiolib.js
	   this.VFO_Sine.generate();
	   this.VFO_Cosine.generate();
	    
	   var Sine = this.VFO_Sine.getMix();	   
	   var Cosine = this.VFO_Cosine.getMix();	 
	   
       var dbl_i = s * Sine; //<-The index variable run up to 44100 samples, so the sine needs 44100 Samples
       var dbl_q = s * Cosine;
       
       //Let the I-channel run through a delay line
       if (this.iDelayIndex >= this.FILTER_LEN / 2) this.iDelayIndex = 0;
       y = this.DelayQueue[this.iDelayIndex];
       this.DelayQueue[this.iDelayIndex++] = dbl_i; //<- DelayLine input
       dbl_i = y;
       
       //Ringbuffer pointer calculation
       this.queue_ptr = (this.queue_ptr + 1) % this.FILTER_LEN;
       this.BufferQueue[this.queue_ptr] = dbl_q; //<- Hilbert trafo input
       var n = this.queue_ptr;
       var out = 0.0;
       
       for(var i=0;i<this.FILTER_LEN;i++){
           out += this.coeffs[i] * this.BufferQueue[n]; // accumulate the Hilbert coeffs with the Q-Channel samples 
           n--;
           if (n < 0) n += this.FILTER_LEN;
       }
      
       dbl_q = out;
       //Ermittlung der beiden Amplituden:
       if (this.maxi < dbl_i) this.maxi = dbl_i;
       if (this.maxq < dbl_q) this.maxq = dbl_q;
       this.Sample = ((this.maxi / this.maxq) * 2) * dbl_q + 2 * dbl_i;
	
	
};

Downmixer.prototype.getMix = function(){
	return this.Sample;
};
module.exports = Downmixer;

Mein Verbesserungsvorschlag wäre, die While Schleife die in Receive steht in die Methode pushSample zu packen,
wenn diese abgearbeitet ist die Methode getMix aufzurufen und ein callback an main.js übergeben nur weiß ich wieder mal nicht wie.

Code:
GstreamerPipe.Receive(function(data){
	downmix.pushSample(data);
});

//callback von downmixer.js
downmix.getMix(function(BlockofSamples){
	//do stuff
});

und pushSample wird zu pushSamples
Code:
Downmixer.prototype.pushSamples = function(BlockOfSamples){
this.NewBlockOfSamples = new Float32Array(BlockOfSamples.length)
var j=0;
while(j!=BlockOfSamples.length){
j++
//Hilbert Trafo Loops

}

//wenn While fertig rufe Methode getMix auf
this.getMix()
}

Downmixer.prototype.getMix = function(){
return this.NewBlockOfSamples // ist sicherlich falsch
//Hier weiß ich nicht weiter

};

Würde mein „Verbesserungsvorschlag“ überhaupt einen Performancevorteil bringen?

Ps:
Kkapsners Implementierung, mit dem Ringbuffer läuft auf nodejs nicht,
ich weiß zwar jetzt nicht mehr genau was das Problem war, aber irgendwas mit der forEach schleife ging nicht… Der Biquad von audiolib.js geht ja auch nicht.

Mfg Xorg1990
 
Mein Verbesserungsvorschlag wäre, die While Schleife die in Receive steht in die Methode pushSample zu packen,
wenn diese abgearbeitet ist die Methode getMix aufzurufen und ein callback an main.js übergeben nur weiß ich wieder mal nicht wie.
wozu das callback? das hast du ja vorher auch nicht benötigt

Würde mein „Verbesserungsvorschlag“ überhaupt einen Performancevorteil bringen?
nein, du sparst doch dann nichts ein
und wenn du in GstreamerPipe.Receive den aufruf downmix.pushSample(data[j]); weglässt(testweise), hast du keine 100% cpulast?
 
hesst schrieb:
wozu das callback? das hast du ja vorher auch nicht benötigt
Doch das ist in der While
Code:
GstreamerPipe.Receive(function(data){
	var j = 0;
	while(j!=data.length){
		j++;
	downmix.pushSample(data[j]);
//Hier habe ich die Samples geholt und ausgegeben
	//console.log(downmix.getMix());
	}
});
Wenn ich die "while(j!=data.length){" in downmix.pushSample packe, weiß ich wider nicht wie ich den den callback hinbekomme.
Die Samples habe ich nur ausgegeben um mir anzuschauen das da nicht NaN oder Undefined steht, auch der Datentyp von Gstreamer stimmt F32 bis max -1, +1.

hesst schrieb:
und wenn du in GstreamerPipe.Receive den aufruf downmix.pushSample(data[j]); weglässt(testweise), hast du keine 100% cpulast?
Dann wird nodejs von Top (ich bewege mich unter Linux/Debian) nicht mal angezeigt.

Nehme ich meinen Verbesserungsvorschlag sind es 80% cpu last das ist schon mal besser als straffe 100%.

Nehme ich das Prototyping ganz weg sind es 50% cpu last laut Top.

Es gäbe noch die Möglichkeit den Hilbert FIR über alle Kerne zu verteilen via Cluster, aber nicht das ich dann auf allen Kernen 100% last habe.
Oder den V8 Garbage Collector manuell aufrufen, im Falle da bleibt was hängen, die Memory Usage geht nämlich auch kontinuierlich hoch.:mad:

Hatte dann noch das Typed Array in Verdacht, das ist Nodjs noch in der Beta aber daran liegt‘s auch nicht.

Habe die V8 mal Protokollieren lassen was da im Hintergrund so abgeht, da es nicht sein kann das Chrome/V8 und NodeJs/V8 so viel Performance unterschied haben.
Zumal NodeJs eigentlich flüssiger laufen sollte.
Anhang anzeigen V8Log.txt
Viel Spaß beim lesen xD.
 
Doch das ist in der While
ahh, ok
Code:
GstreamerPipe.Receive(function(data){
	var j = 0;
	while(j!=data.length){
		j++;
	downmix.pushSample(data[j]);
//Hier habe ich die Samples geholt und ausgegeben
	//console.log(downmix.getMix());
	}
});
ob da nun while() { downmix.pushSample } steht, oder downmix.pushSamples und in dieser while() { downmix.pushSample }, ist ja das gleiche
dein downmix.getMix(); kannst du im 2. fall auch einfach dort hinschreiben

Dann wird nodejs von Top (ich bewege mich unter Linux/Debian) nicht mal angezeigt.
dann hat dein algorithmus mit dem verarbeiten der daten richtig gut zu tun, bzw. wird wohl nicht mal fertig ehe neue daten eintreffen, dann musst du an dieser stelle optimieren

Nehme ich meinen Verbesserungsvorschlag sind es 80% cpu last das ist schon mal besser als straffe 100%.
dann machst du aber irgendwas anders, als beschrieben. ob du das while direkt aufrufst, oder in eine funktion packst, sollte egal sein.
kann es sein, dass du einmal console.log(downmix.getMix()); ausführst, und einmal nicht? io-operationen sind immer langsamm, und wenn viel gelogt wird, kann es sein, daß das die zeit verbraucht
 
hesst schrieb:
bzw. wird wohl nicht mal fertig ehe neue daten eintreffen
Genau das habe ach schon in Verdacht gehabt, deswegen habe ich die gespawnte Gstreamer Pipeline via Taskkill getötet. Ergebnis ist, das Node weiterhin auf 100% bleibt.

hesst schrieb:
kann es sein, dass du einmal console.log(downmix.getMix()); ausführst, und einmal nicht?
Ne das hätte ich ja gesehen, aber ich muss meine Aussage zurückziehen, da bei allen drei Interpretationen 100% cpu last ist, es dauert nur unterschiedlich lang bis das passiert.

Das Problem muss wohl in der Engine von NodeJs liegen.:mad:


hesst schrieb:
dein downmix.getMix(); kannst du im 2. fall auch einfach dort hinschreiben
Wie meinen??

Ich habe das jetzt so glöst:

main.js:
Code:
GstreamerPipe.Receive(function(data){
	downmix.pushSamples(data);
});

downmix.getMix(function(newBlockOfSamples){
	console.log(newBlockOfSamples.length);
});

Downmixer.js:
Code:
Downmixer.prototype.pushSamples = function(BlockofSamples) {
    var SamplesBuffer = new Float32Array(BlockofSamples.length);
    var j = 0;
    while (j = !BlockofSamples.length) {
        j++;
        //generate the sine samples from audiolib.js
        this.VFO_Sine.generate();
        this.VFO_Cosine.generate();

        var Sine = this.VFO_Sine.getMix();
        var Cosine = this.VFO_Cosine.getMix();

        var dbl_i = BlockofSamples[j] * Sine; //<-The index variable run up to 44100 samples, so the sine needs 44100 Samples
        var dbl_q = BlockofSamples[j] * Cosine;

        //Let the I-channel run through a delay line
        if (this.iDelayIndex >= this.FILTER_LEN / 2) this.iDelayIndex = 0;
        y = this.DelayQueue[this.iDelayIndex];
        this.DelayQueue[this.iDelayIndex++] = dbl_i; //<- DelayLine input
        dbl_i = y;

        //Ringbuffer pointer calculation
        this.queue_ptr = (this.queue_ptr + 1) % this.FILTER_LEN;
        this.BufferQueue[this.queue_ptr] = dbl_q; //<- Hilbert trafo input
        var n = this.queue_ptr;
        var out = 0.0;

        for (var i = 0; i < this.FILTER_LEN; i++) {
            out += this.coeffs[i] * this.BufferQueue[n]; // accumulate the Hilbert coeffs with the Q-Channel samples 
            n--;
            if (n < 0) n += this.FILTER_LEN;
        }

        dbl_q = out;
        //Ermittlung der beiden Amplituden:
        if (this.maxi < dbl_i) this.maxi = dbl_i;
        if (this.maxq < dbl_q) this.maxq = dbl_q;
        var Sample = ((this.maxi / this.maxq) * 2) * dbl_q + 2 * dbl_i;

        SamplesBuffer[j] = this.Sample;
    } //ende while 
    this.newBlockofSamples = SamplesBuffer;
    //console.log(this.newBlockofSamples.length); <- 17538
    this.getMix();
};



Downmixer.prototype.getMix = function(cb) {
    return cb(this.newBlockofSamples);
};

Damit wird zwar ein Callback ausgelöst aber ich erhalte ein Fehler:
Code:
/home/xorg1990/workspace/DSP Server/main.js:50
	console.log(newBlockOfSamples.length);
	                             ^
TypeError: Cannot read property 'length' of undefined
    at /home/xorg1990/workspace/DSP Server/main.js:50:31
    at Downmixer.getMix (/home/xorg1990/workspace/DSP Server/requires/Downmixer.js:122:12)
    at Object.<anonymous> (/home/xorg1990/workspace/DSP Server/main.js:49:9)
    at Module._compile (module.js:456:26)
    at Object.Module._extensions..js (module.js:474:10)
    at Module.load (module.js:356:32)
    at Function.Module._load (module.js:312:12)
    at Function.Module.runMain (module.js:497:10)
    at startup (node.js:119:16)
    at node.js:906:3

Irwi scheint die Methode getMix(), this.newBlockofSamples nicht zu kennen.

Wenn ich das so schreibe:
Code:
   } //ende while 
    //console.log(this.newBlockofSamples.length); <- 17538
    this.getMix(SamplesBuffer);
};



Downmixer.prototype.getMix = function(cb, SamplesBuffer) {
    return cb(SamplesBuffer);
};
geht auch nix los.:(
 
da bei allen drei Interpretationen 100% cpu last ist, es dauert nur unterschiedlich lang bis das passiert.
ok
was ist der 3. fall?

Code:
GstreamerPipe.Receive(function(data){
	downmix.pushSamples(data);
        downmix.getMix();
});
Ich habe das jetzt so glöst:
...
Code:
downmix.getMix(function(newBlockOfSamples){
	console.log(newBlockOfSamples.length);
});
jetzt verstehe ich dein problem, vorher hast du jedes element im array einzeln in pushSample verarbeitet und dann mit getMix weiter verarbeitet, jetzt hast du in pushSamples das ganze array, verarbeitest alle und musst/willst jetzt auch in getMix mit einem array arbeiten.
da ist die frage, wie soll es denn (möglichst) aufgebaut sein?
* getMix soll in main oder Downmixer.js aufgerufen oder definiert werden?
* getMix soll nach möglichkeit einzelne ergebnisse aus pushSample oder alle aus pushSamples verarbeiten?

Damit wird zwar ein Callback ausgelöst aber ich erhalte ein Fehler
das:
Code:
downmix.getMix(function(newBlockOfSamples){
	console.log(newBlockOfSamples.length);
});
Code:
    ...
    //console.log(this.newBlockofSamples.length); <- 17538
    this.getMix();
}
Code:
Downmixer.prototype.getMix = function(cb, SamplesBuffer) {
    return cb(SamplesBuffer);
};
passt alles nicht zusammen,
du deklarierst im 3. teil getMix als funktion mit 2 parametern, und rufst sie im 2. teil ohne auf und im 1. teil mit nur dem callback, ohne SamplesBuffer und einfach so global in main

beschreib mal, wie es nach möglichkeit strukturiert sein sollte, wer soll getMix wo nach möglichkeit wie aufrufen.

- - - Aktualisiert - - -

vermutlich soll es so etwa aussehen:
Code:
GstreamerPipe.Receive(function(data)
{
  console.log(data);
});

Code:
Downmixer.prototype.Receive = function(cb)
{
  this.GstLaunch.stdout.on('data', this.pushSamples.bind(this, cb));
}
Downmixer.prototype.pushSamples = function(cb, BlockOfSamples)
{
  for (var j = 0; j < BlockOfSamples.length; ++j)
  {
    this.pushSample(BlockOfSamples[j]);
    cb(this.getMix());
  }
}
Downmixer.prototype.pushSample(data)
{
  // deine alte pushSample funktion
}
Downmixer.prototype.getMix = function(){
	return this.Sample;
};
 
hesst schrieb:
jetzt verstehe ich dein problem, vorher hast du jedes element im array einzeln in pushSample verarbeitet und dann mit getMix weiter verarbeitet, jetzt hast du in pushSamples das ganze array, verarbeitest alle und musst/willst jetzt auch in getMix mit einem array arbeiten.
Genau, zuerst hatte ich mit jedem Element im Array die Methode pushSample aufgerufen und in derselben Schleife GetMix.

Jetzt ist es so, dass ich das komplette Array an pushSamples übergebe und wenn die while durch ist,
brauch ich einen callback wenn möglich mit den Namen getMix der mir das verarbeite Array eben wieder zurück gibt, nach main.js.

hesst schrieb:
* getMix soll in main oder Downmixer.js aufgerufen oder definiert werden?
Aufgerufen wird getMix() wenn die while in pushSamples durch ist, das verarbeitet Array soll aber nach main.js.


hesst schrieb:
* getMix soll nach möglichkeit einzelne ergebnisse aus pushSample oder alle aus pushSamples verarbeiten?
alle aus pushSamples.
 
dann so
Code:
GstreamerPipe.Receive(function(data)
{
  for (var j = 0; j < data.length; ++j)
  {
    console.log(data[j]);
  }
});
Code:
function Downmixer()
{
  // zusätzlich:
  this.Samples = [];
}
Downmixer.prototype.Receive = function(cb)
{
  this.GstLaunch.stdout.on('data', this.pushSamples.bind(this, cb));
}
Downmixer.prototype.pushSamples = function(cb, BlockOfSamples)
{
  this.Samples = [];
  for (var j = 0; j < BlockOfSamples.length; ++j)
  {
    this.Samples.push(this.pushSample(BlockOfSamples[j]));
  }
  cb(this.getMix());
}
Downmixer.prototype.pushSample(data)
{
  // deine alte pushSample funktion
  // zusätzlich:
  return Sample; // return this.Sample; aber Sample kann jetzt lokal liegen und muss kein Member mehr sein
}
Downmixer.prototype.getMix = function(){
	return this.Samples;
};
 
Hä? Nee, du hast da was falsch verstanden hesst. pushSamples ist dasselbe wie pushSample, das S hängt da aus Grammatik gründen hinten dran, Plural.

Mit dem Array this.Samples = [] hast du dich auch in was rein manövriert, mit Array meinte ich ein Typisiertes Array oder in Nodjes ein "Buffer Objekt“.

Dann fällt mir auf das du die Methode bind() verwendest, das ist eine Erfindung aus den Hause Mozilla und steht unter Nodejs nicht zu Verfügung. Da bin ich selber schon 100mal drauf reingefallen.

Wir drücken noch mal den Restknopf im Gehirn und ich erkläre was funktioniert und was nicht:

Code:
//Hier Übergabe ich meine buffer an die Methode pushSamples
GstreamerPipe.Receive(function(data){
	downmix.pushSamples(data);
});// das geht einwadfrei



//downmix.getMix soll der callback sein
downmix.getMix(function(newBlockOfSamples){
	console.log(newBlockOfSamples.length);
});// callback wird nie ausgelöst

In Downmixer.js gibt es die Methode pushSamples, da findet der Verarbeitungsprozess statt, und wenn dieser fertig ist brauche ich (logisch) einen callback zurück nach main.js

Nachmals zu Vervollständigung:
Code:
Downmixer.prototype.pushSample(BufferMitSamples)
{
  while(){ 
    verabeitung... ...
   }wenn while fertig mache callback, wie möchte ich nur wissen?:-(
}

Was in NodeJS nicht funktionier ist:
.bind()

getMix : function(){} <- unexpected identifier

und return function() {} geht auch nicht unexpected identifier bei (), es sei denn in der Klammer steht was drinnen.
 
Hä? Nee, du hast da was falsch verstanden hesst. pushSamples ist dasselbe wie pushSample, das S hängt da aus Grammatik gründen hinten dran, Plural.
ok, ich dachte pushSample geht uber ein element aus dem array das recive übergeben wird, und pushSamples über das gesammte array

Mit dem Array this.Samples = [] hast du dich auch in was rein manövriert, mit Array meinte ich ein Typisiertes Array oder in Nodjes ein "Buffer Objekt“.
da sehe ich dann aber auch nicht warum

Dann fällt mir auf das du die Methode bind() verwendest, das ist eine Erfindung aus den Hause Mozilla und steht unter Nodejs nicht zu Verfügung. Da bin ich selber schon 100mal drauf reingefallen.
bind ist standard, würde mich wundern, wenn nodejs das nicht unterstützt, sonst nimm ein polyfill

Wir drücken noch mal den Restknopf im Gehirn und ich erkläre was funktioniert und was nicht:
ich weiß dann nicht, wie es gehen soll

- - - Aktualisiert - - -

In Downmixer.js gibt es die Methode pushSamples, da findet der Verarbeitungsprozess statt, und wenn dieser fertig ist brauche ich (logisch) einen callback zurück nach main.js
ich habs nochmal gelesen, ich versteh es immer noch so
 
hesst schrieb:
ich weiß dann nicht, wie es gehen soll
Indem man mit dem Kopf durch die Wand rennt

Also nochmal, wenn wir jetzt unseren Wissensstand nicht auf einen Ebene bringen, dann weesch och nicht weiter.
in main.js steht das
Code:
GstreamerPipe.Receive(function(data){
	downmix.pushSamples(data);

       console.log(downmix.getMix().length); 
       //17568 usw.
});

in Downmixer.js das,
Code:
Downmixer.prototype.pushSamples = function(BlockofSamples) {
    var SamplesBuffer = new Float32Array(BlockofSamples.length);
    var j = 0;
    while (j = !BlockofSamples.length) {
        j++;
        //generate the sine samples from audiolib.js
        this.VFO_Sine.generate();
        this.VFO_Cosine.generate();

        var Sine = this.VFO_Sine.getMix();
        var Cosine = this.VFO_Cosine.getMix();

        var dbl_i = BlockofSamples[j] * Sine; //<-The index variable run up to 44100 samples, so the sine needs 44100 Samples
        var dbl_q = BlockofSamples[j] * Cosine;

        //Let the I-channel run through a delay line
        if (this.iDelayIndex >= this.FILTER_LEN / 2) this.iDelayIndex = 0;
        y = this.DelayQueue[this.iDelayIndex];
        this.DelayQueue[this.iDelayIndex++] = dbl_i; //<- DelayLine input
        dbl_i = y;

        //Ringbuffer pointer calculation
        this.queue_ptr = (this.queue_ptr + 1) % this.FILTER_LEN;
        this.BufferQueue[this.queue_ptr] = dbl_q; //<- Hilbert trafo input
        var n = this.queue_ptr;
        var out = 0.0;

        for (var i = 0; i < this.FILTER_LEN; i++) {
            out += this.coeffs[i] * this.BufferQueue[n]; // accumulate the Hilbert coeffs with the Q-Channel samples 
            n--;
            if (n < 0) n += this.FILTER_LEN;
        }

        dbl_q = out;
        //Ermittlung der beiden Amplituden:
        if (this.maxi < dbl_i) this.maxi = dbl_i;
        if (this.maxq < dbl_q) this.maxq = dbl_q;
        var Sample = ((this.maxi / this.maxq) * 2) * dbl_q + 2 * dbl_i;

        SamplesBuffer[j] = this.Sample;
    } //ende while 

    this.newBlockofSamples = SamplesBuffer;
};

Downmixer.prototype.getMix = function() {
    return this.newBlockofSamples;
};
Da ist halt das Problem das downmix.pushSamples(data) und downmix.getMix().length synchron ausgeführt werden .

Frage: wie bekomme ich es hin, dass ich einen separaten callback habe?
Code:
downmix.getMix(function(BlockOfSamplesDerVonVerarbeitungZurückKommt){
	console.log(BlockOfSamplesDerVonVerarbeitungZurückKommt.length);
});

Was muss ich in Downmixer.prototype.getMix reinschreiben damit ich this.newBlockofSamples in main.js zurück kommt, aber erst nachdem die while fertig ist.
 
Da ist halt das Problem das downmix.pushSamples(data) und downmix.getMix().length synchron ausgeführt werden .
was meinst du mit synchron? also synchron im sinne des ablaufs ist es auf jeden fall

Frage: wie bekomme ich es hin, dass ich einen separaten callback habe?
sry, aber ich versteh die frage - das ganze problem womöglich - nicht

Was muss ich in Downmixer.prototype.getMix reinschreiben damit ich this.newBlockofSamples in main.js zurück kommt, aber erst nachdem die while fertig ist.
return this.newBlockofSamples; aber du meinst sicher was anderes
 
hesst schrieb:
also synchron im sinne des ablaufs ist es auf jeden fall
Genau das meine ich auch und das ist das Problem getMix wird schon aufgerufen ehe die while überhabt fertig ist, dass führt zu 100% cpu last.

hesst schrieb:
sry, aber ich versteh die frage - das ganze problem womöglich - nicht
Seufz, wenn ich nur wüsste wie ich das beschreiben soll:dejection:

Das ist jetzt der Code der funktioniert aber wie erwähnt mit 100% cpu last.
Code:
GstreamerPipe.Receive(function(data){
	downmix.pushSamples(data);

       console.log(downmix.getMix().length); 
       //17568 usw.
});

Daraus soll aber das werden:

Code:
GstreamerPipe.Receive(function(data){
	downmix.pushSamples(data);
});/ende GstreamerPipe.Receive


downmix.getMix(function(newBlockOfSamples){
	console.log(newBlockOfSamples.length);
});// downmix.getMix wird nie ausglöst
Ich bekomme this.newBlockofSamples einfach nicht nach main.js, entweder wird downmix.getMix nicht ausgelöst oder mit einer Fehlermeldung.

Für mich als newbie ist der Werdegang so: Nach der while löse ich die Methode getMix aus, diese enthält einen calback der zur man.js führe soll

in Form eines codes so:
Code:
    } //ende while 

    this.newBlockofSamples = SamplesBuffer;
    this.getMix();//Methode getMix ausführen 
};//ende pushSamples

Downmixer.prototype.getMix = function(cb) {
    return cb(this.newBlockofSamples)
};
Das führt zu folgender Fehlermeldung:
„TypeError: Cannot read property ‚length‘ of undefined“ in main.js

Das sagt mir das downmix.getMix(function(newBlockOfSamples) schon mal ausgelöst wird aber newBlockOfSamples ist nicht bekannt. Warum???
 
Zuletzt bearbeitet:
Genau das meine ich auch und das ist das Problem getMix wird schon aufgerufen ehe die while überhabt fertig ist, dass führt zu 100% cpu last.
das dachte ich hatten wir geklärt, die cpu last bringst du so nicht runter

Für mich als newbie ist der Werdegang so: Nach der while löse ich die Methode getMix aus, diese enthält einen calback der zur man.js führe soll
prinzipiell geht das so, wie in #6 #8
 
Dann fällt mir auf das du die Methode bind() verwendest, das ist eine Erfindung aus den Hause Mozilla und steht unter Nodejs nicht zu Verfügung. Da bin ich selber schon 100mal drauf reingefallen.
Das kann nicht sein. .bind() ist in ECMA-5 definiert und V8 ist da konform. Auch funktioniert .bind() in meiner nodejs Installation. Ich würde das mal neu installieren. Welche Version verwendest du?

Auch sollte der RingBuffer aus dem anderen Thread funktionieren. Welche Fehlermeldung kommt denn da?

Das ist jetzt der Code der funktioniert aber wie erwähnt mit 100% cpu last.
Der Code ist meiner Meinung nach nicht das Problem.

Aber zu deinem Problem: wenn du die .getMix() direkt in der main.js aufrufst, wird die ja direkt aufgerufen und du hast da natürlich noch keine Daten zur Verfügung. Um da einen separaten Callback zu haben, musst an deinem Objekt irgendwo die Funktion speichern und diese dann am Ende der pushSamples() aufrufen. In etwa so:
Downmixer.js
Code:
Downmiser.prototype.pushSamplesCallback = function(){};
Downmixer.prototype.pushSamples(...){
	...
	while (...){
		....
	}
	this.pushSamplesCallback(SamplesBuffer);
};
main.js
Code:
GstreamerPipe.Receive(function(data){
	downmix.pushSamples(data);
});


downmix.pushSamplesCallback = function(newBlockOfSamples){
	console.log(newBlockOfSamples.length);
};

Bin aber echt der Meinung, dass das dein Problem nicht lösen wird.

Zuerst würde ich nodejs neu aufsetzen. Wenn die grundlegenden Probleme (.bind, RingBuffer, audiolib.js) immer noch bestehen, musst du das Ganze mal auf einer anderen Maschine (ev. auch anderes OS) ausprobieren.

Wenn nur noch die 100% als Problem übrig sind, muss am Code optimiert werden - aber ich hab' da ein paar andere Sachen im Kopf, die helfen könnten, als du.
 
hesst schrieb:
das dachte ich hatten wir geklärt, die cpu last bringst du so nicht runter
Und wenn ich dir doch sage:
Bildschirmfoto vom 2014-08-28 18_51_29.png
Sogar mit Ausgabe!




Aus #8 habe ich das gemacht (zur Vollständigkeit halber den kompletten Code)
main.js:
Code:
var Gstreamer = require('./requires/child.js');
var Downmixer = require('./requires/Downmixer.js');


//locals for the  Gstreamer Pipline;
var SampleRate = 192000;
var cmd = 'gst-launch-1.0';
var options = null;
var args = ['fdsrc fd=0', '!', 'audioparse', '!', 'audioresample quality=10', '!', 'audio/x-raw, rate='+SampleRate+'', '!', 'audioconvert', '!', 'capsfilter caps=audio/x-raw, rate='+SampleRate+', channels=1, format=F32LE, signed=true', '!', 'queue2 max-size-bytes=131027, min-threshold-bytes=32768', '!','fdsink fd=1'];

// create Gstreamer Pilpline
var GstreamerPipe = new Gstreamer(cmd, args, options);

//freq, Samplerate
var downmix = new Downmixer(1200, SampleRate);


GstreamerPipe.Receive(function(data){
	
	downmix.pushSamples(data, function(data){
		 console.log(data.length);
	});

	
});

Downmixer.js:
Code:
function Downmixer(VFO_Freq, Samplerate) {
    this.FILTER_LEN = 100; //FIR Hilbert length 

    this.VFO_Sine = require('../node_modules/audiolib').Oscillator(Samplerate, VFO_Freq);
    this.VFO_Cosine = require('../node_modules/audiolib').Oscillator(Samplerate, VFO_Freq);
    this.VFO_Sine.waveShape = 'sine';
    this.VFO_Cosine.waveShape = 'cosine';
    this.queue_ptr = 0;
    this.iDelayIndex = 0;

    this.maxi = 0.001;
    this.maxq = 0.001;
    this.DelayQueue = new Float32Array(this.FILTER_LEN);
    this.BufferQueue = new Float32Array(this.FILTER_LEN);
    this.calcCoeff();
}

Downmixer.prototype.calcCoeff = function() {
    var HILBERT_ARRAY = new Float64Array(this.FILTER_LEN);

    HILBERT_ARRAY[this.FILTER_LEN] = 0;
    for (var jj = 0; jj <= this.FILTER_LEN / 2; jj++) {
        var coeff = jj & 1 ? 2.0 / ((this.FILTER_LEN / 2 - jj) * Math.PI) : 0.0; //<- Implementierung W Kiefer
        //var coeff = jj&1 ? 2.0/(jj*Math.PI) : 0.0;//<- Implementierung Wolf Büscher
        //var coeff = 1/((jj-FILTER_LEN/2)-0.5)/Math.PI; //<- Eigene Implementierung  der Koeffizienten
        HILBERT_ARRAY[jj] = coeff;
        HILBERT_ARRAY[this.FILTER_LEN - jj] = -coeff;
    }
    this.coeffs = HILBERT_ARRAY;
};

/*
Downmixer.prototype.pushSample = function(s){
		//generate the sine samples from audiolib.js
	   this.VFO_Sine.generate();
	   this.VFO_Cosine.generate();
	    
	   var Sine = this.VFO_Sine.getMix();	   
	   var Cosine = this.VFO_Cosine.getMix();	 
	   
       var dbl_i = s * Sine; //<-The index variable run up to 44100 samples, so the sine needs 44100 Samples
       var dbl_q = s * Cosine;
       
       //Let the I-channel run through a delay line
       if (this.iDelayIndex >= this.FILTER_LEN / 2) this.iDelayIndex = 0;
       y = this.DelayQueue[this.iDelayIndex];
       this.DelayQueue[this.iDelayIndex++] = dbl_i; //<- DelayLine input
       dbl_i = y;
       
       //Ringbuffer pointer calculation
       this.queue_ptr = (this.queue_ptr + 1) % this.FILTER_LEN;
       this.BufferQueue[this.queue_ptr] = dbl_q; //<- Hilbert trafo input
       var n = this.queue_ptr;
       var out = 0.0;
       
       for(var i=0;i<this.FILTER_LEN;i++){
           out += this.coeffs[i] * this.BufferQueue[n]; // accumulate the Hilbert coeffs with the Q-Channel samples 
           n--;
           if (n < 0) n += this.FILTER_LEN;
       }
      
       dbl_q = out;
       //Ermittlung der beiden Amplituden:
       if (this.maxi < dbl_i) this.maxi = dbl_i;
       if (this.maxq < dbl_q) this.maxq = dbl_q;
       this.Sample = ((this.maxi / this.maxq) * 2) * dbl_q + 2 * dbl_i;
	
	
};
*/

Downmixer.prototype.pushSamples = function(BlockofSamples, cb) {
    var SamplesBuffer = new Float32Array(BlockofSamples.length);
    var j = 0;
    while (j = !BlockofSamples.length) {
        j++;
        //generate the sine samples from audiolib.js
        this.VFO_Sine.generate();
        this.VFO_Cosine.generate();

        var Sine = this.VFO_Sine.getMix();
        var Cosine = this.VFO_Cosine.getMix();

        var dbl_i = BlockofSamples[j] * Sine; //<-The index variable run up to 44100 samples, so the sine needs 44100 Samples
        var dbl_q = BlockofSamples[j] * Cosine;

        //Let the I-channel run through a delay line
        if (this.iDelayIndex >= this.FILTER_LEN / 2) this.iDelayIndex = 0;
        y = this.DelayQueue[this.iDelayIndex];
        this.DelayQueue[this.iDelayIndex++] = dbl_i; //<- DelayLine input
        dbl_i = y;

        //Ringbuffer pointer calculation
        this.queue_ptr = (this.queue_ptr + 1) % this.FILTER_LEN;
        this.BufferQueue[this.queue_ptr] = dbl_q; //<- Hilbert trafo input
        var n = this.queue_ptr;
        var out = 0.0;

        for (var i = 0; i < this.FILTER_LEN; i++) {
            out += this.coeffs[i] * this.BufferQueue[n]; // accumulate the Hilbert coeffs with the Q-Channel samples 
            n--;
            if (n < 0) n += this.FILTER_LEN;
        }

        dbl_q = out;
        //Ermittlung der beiden Amplituden:
        if (this.maxi < dbl_i) this.maxi = dbl_i;
        if (this.maxq < dbl_q) this.maxq = dbl_q;
        var Sample = ((this.maxi / this.maxq) * 2) * dbl_q + 2 * dbl_i;

        SamplesBuffer[j] = this.Sample;
    } //ende while #
    this.NewBlockOfSamples = SamplesBuffer;
    if(cb != undefined && typeof cb == 'function') cb(this.getMix());
};



Downmixer.prototype.getMix = function() {
	return this.NewBlockOfSamples;
};


module.exports = Downmixer;
Dieser Code und der Screenshot gehören zusammen, dass sind 2,6% CPU Last.
Bin gerade selber ein wenig verwirrt warum das so wenig ist auch nach 15min noch, 30% wär ja plausibel aber so wenig:confused:

Ich weiß jetzt schon was du mir sagen wirst: Warum rufst du im callback this.getMix auf, man könnte ja gleich SamplesBuffer übergeben.

A:
Ich möchte ja eigentlich den callback vom downmixer außerhalb von den GstreamerPipe.Receive callback haben.
Wenn ich so weiter mache habe ich immer mehr callbacks im callback.
z.B.:
Code:
GstreamerPipe.Receive(function(data){
         //callback 1
	downmix.pushSamples(data, function(data){
                callback 2
		filter1.pushSamples(data, function(data){
                callback3
                //usw...
);

Das ist das beste was ich aus #8 machen konnte:D. Aussehen soll‘s aber wie in #13
 
Und wenn ich dir doch sage:
Anhang anzeigen 4354
Sogar mit Ausgabe!
das kann nicht sein, dann wird hier irgendwas nicht gemacht, oder im alten läuft was komisch
der einzige unterschied ist ja, dass das cb erst am ende der schleife und nicht in jedem durchgang gerufen wird. aber im cb machst du ja nichts.

Ich weiß jetzt schon was du mir sagen wirst: Warum rufst du im callback this.getMix auf, man könnte ja gleich SamplesBuffer übergeben.
nee, finde ich gut

Ich möchte ja eigentlich den callback vom downmixer außerhalb von den GstreamerPipe.Receive callback haben.
ich verstehs nicht

Wenn ich so weiter mache habe ich immer mehr callbacks im callback.
ja, anders geht es nicht, wenn du mit cb arbeiten willst, sonst musst du pushSamples die werte als returnwert zurückgeben lassen
 
kkapsner schrieb:
Ich würde das mal neu installieren. Welche Version verwendest du?
version 0.10.11 stable selbst kompiliert. Neu Installation mache ich ich gleich morgen.



kkapsner schrieb:
Auch sollte der RingBuffer aus dem anderen Thread funktionieren. Welche Fehlermeldung kommt denn da?
Du fragst mich jetzt Sachen das ist schon 4Tage her. Da ich deinen Ringbuffer eh nicht versteh, habe ich das auch nicht weiter beachtet und gelöscht. :mask:
Der Fehler verwies auf diese Zeile func(this.get(i), i, this);

kkapsner schrieb:
Um da einen separaten Callback zu haben, musst an deinem Objekt irgendwo die Funktion speichern und diese dann am Ende der pushSamples() aufrufen. In etwa so:
Kkapsner, das sieht gut aus, wenn ich morgen nodejs neu aufgesetzt habe werde ich das mal probieren.

Aber warum nicht so:
Code:
downmix.pushSamplesCallback(function(newBlockOfSamples){
	console.log(newBlockOfSamples.length);
});
Das würde besser ins Bild passen:grin:

- - - Aktualisiert - - -

Alter mir tun schon die Finger weh.:(

hesst schrieb:
das kann nicht sein, dann wird hier irgendwas nicht gemacht, oder im alten läuft was komisch
der einzige unterschied ist ja, dass das cb erst am ende der schleife und nicht in jedem durchgang gerufen wird. aber im cb machst du ja nichts.
Wenn ich nur wüsste wie ich das beweisen könnte mit der cpu last, habe schon an ein Video gedacht.

kkapsner schrieb:
wenn du die .getMix() direkt in der main.js aufrufst, wird die ja direkt aufgerufen und du hast da natürlich noch keine Daten zur Verfügung.
das wird wohl die Ursache für die hohe cpu last sein. Andernfalls ging die ja nach einen Taskkill nicht wieder zurück:confused:

hesst schrieb:
ich verstehs nicht
aber Korbinian.

In diesem sinne :sleeping:
 
so, jetzt hab ichs nochmal gelesen.
deine puschSamples funktion ist deine alte puschSample mit einer sleife drumherum. richtig?
wenn ja, würde ich puschSamples zusätzlich zur puschSample funktion implementieren, wobei puschSamples in der schleife puschSample aufruft.
ist kein muss, ich fänds nur übersichtiger

Kkapsner, das sieht gut aus, wenn ich morgen nodejs neu aufgesetzt habe werde ich das mal probieren.

Aber warum nicht so:
Code:
downmix.pushSamplesCallback(function(newBlockOfSamples){
	console.log(newBlockOfSamples.length);
});
du willst also nur nicht die callbacks schachteln, ist das das einzige?
ich würds zwar machen, weil das wiederum auf einem blick den ablauf sichtbar macht, aber wenn du das nicht willst, kannst du das auch so machen.
das mit deiner pushSamplesCallback funktion geht auch. alternativ kannst du auch einen zwischenweg gehen, und das callback außen implementieren aber weiter als parameter übergeben, das macht es wieder ein wenig übersichtliger.
also, meine favorisierte variante: #6
als externe funktion: der rest bleibt, wie #6, main.js
Code:
GstreamerPipe.Receive(mixerCallback);
function mixerCallback(data)
{
  console.log(data);
}
oder als explizite property mit funktion:
Code:
GstreamerPipe.Receive();
downmix.pushSamplesCallback(function(newBlockOfSamples){
	console.log(newBlockOfSamples.length);
});
// ist das gleiche wie: downmix.samplesCallback = function(newBlockOfSamples){... nur mit extra funktion
Code:
Downmixer.prototype.Receive = function()
{
  this.GstLaunch.stdout.on('data', this.pushSamples.bind(this));
}
Downmixer.prototype.pushSamples = function(BlockOfSamples)
{
  for (var j = 0; j < BlockOfSamples.length; ++j)
  {
    this.pushSample(BlockOfSamples[j]);
    // die abprüfungen lass ich mal alle weg, nur das prinzip
    this.samplesCallback(this.getMix());
  }
}
Downmixer.prototype.pushSample(data)
{
  // deine alte pushSample funktion
}
Downmixer.prototype.getMix = function(){
	return this.Sample;
};
Downmixer.prototype.pushSamplesCallback = function(cb){
	this.samplesCallback = cb;
};
Downmixer.prototype.samplesCallback = null;
ob du in deinem cb jetzt die werte aus den einzelnen pushSample durchläufen oder nur am ende aus pushSamples haben willst, hab ich noch nicht ganz verstanden, spielt aber dafür auch erst mal keine rolle
auch habe ich mal als grundlage #6 genommen, du hast glaube ich noch eine ebene mehr drinn - scheiße, ich machs doch nochmal für fall 2 und 3, den 1. willst du ja anscheinend nicht
fall 2(wieder nur die main, rest bleibt ja gleich):
Code:
GstreamerPipe.Receive(mixerCallback);
function receiveCallback(data)
{
  downmixer.pushSamples(mixerCallback);
}
function mixerCallback(data)
{
  console.log(data);
}
fall 3:
Code:
GstreamerPipe.Receive();
GstreamerPipe.pushReceiveCallback(function(data){
	downmix.pushSamles(data);
});
downmix.pushSamplesCallback(function(newBlockOfSamples){
	console.log(newBlockOfSamples.length);
});
Code:
// dein Gstreamer muss genau wie der Downmixer angepasst werden und das cb als property speichern
Code:
Downmixer.prototype.pushSamples = function(BlockOfSamples)
{
  for (var j = 0; j < BlockOfSamples.length; ++j)
  {
    this.pushSample(BlockOfSamples[j]);
    // die abprüfungen lass ich mal alle weg, nur das prinzip
    this.samplesCallback(this.getMix());
  }
}
Downmixer.prototype.pushSample(data)
{
  // deine alte pushSample funktion
}
Downmixer.prototype.getMix = function(){
	return this.Sample;
};
Downmixer.prototype.pushSamplesCallback = function(cb){
	this.samplesCallback = cb;
};
Downmixer.prototype.samplesCallback = null;

Alter mir tun schon die Finger weh.:(
:grin:

Wenn ich nur wüsste wie ich das beweisen könnte mit der cpu last, habe schon an ein Video gedacht.
du musst das nicht beweisen, ich glaub dir das schon, ABER das ganze ändert nichts am laufzeitverhalten, wenn da unterschiede sind, läuft es irgendwo nicht so, wie du denkst.

das wird wohl die Ursache für die hohe cpu last sein. Andernfalls ging die ja nach einen Taskkill nicht wieder zurück:confused:
nein
 
Cool hesst, du hast es nun doch verstanden was ich will. Mit diesem Syntax kann ich auch was anfangen.

Ich habe nodejs auf die Aktuelle Version geupdated das Problem mit audiolib.js und deren biquad besteht immer noch. Korbinian's Ringbuffer funzt auch ohne murren.
.bind() kann ich nicht testen, mir fällt auf die schnelle nichts ein wo ich das unterbringen könnte.


hesst schrieb:
du musst das nicht beweisen, ich glaub dir das schon, ABER das ganze ändert nichts am laufzeitverhalten, wenn da unterschiede sind, läuft es irgendwo nicht so, wie du denkst.
Ja ich weiß, ich bin ja auch nicht von gestern, habe auch schon Atmega Mikroprozessoren programmiert in C, unter anderem habe ich auf meiner alten ps2 ein SDR am laufen,
da habe ich mir zutritt auf die VU‘s beschafft und die machen die FFT. Es gibt ja auch welche die machen DSP auf einer Grafikkarte TuTwente z.B.

Das ist das was ich letztens mit dem Array ankündigen wollte, es gibt in C keine gemischt Typisierten Arrays, das nennt sich da struct. Es ist einfach eine Gewohnheitssache man sieht, Int32Array und weiß was los ist. Aber das alles ist ein anderes Thema.


Ich habe trotzdem ein Video gemacht. Seht selbst:
http://dm4tr.bplaced.net/Hilbert/CpuLoad.rar

Das ist das, was ich in #16 gepostet habe.
 
Zuletzt bearbeitet:
Zurück
Oben