I'm trying to get a precise clock that is not influenced by other processes inside the app.
I currently use System.nanoTime() like below inside a thread.
I use to calculate the timing of each of the sixteen step.
Currently timed operations have sometime a perceptible delay that i try to fix.
I would like to know if there is a more precise way to obtaining timed operations, maybe by check the internal soundcard clock and use it to generate the timing i need.
I need it to send midi notes from android device to external audio sinthetizers and for audio i need precise timing
Is there anyone who can help me improve this aspect?
Thanks
cellLength = (long)(0.115*1000000000L);
for ( int x = 0; x < 16; x++ ) {
noteStartTimes[x] = x*cellLength ;
}
long startTime = System.nanoTime();
index = 0;
while (isPlaying) {
if (noteStartTimes[index] < System.nanoTime() - startTime) {
index++ ;
if (index == 16) { //reset things
startTime = System.nanoTime() + cellLength;
index = 0 ;
}
}
}
For any messages that you receive, the onSend callback gives you a timestamp.
For any messages that you send, you can provide a timestamp.
These timestamps are based on System.nanoTime(), so your own code should use this as well.
If your code is delayed (by its own processing, or by other apps, or by background services), System.nanoTime() will accurately report the delay. But no timer will function can make your code run earlier.
Related
I'm curious about this.
I wanted to check which function was faster, so I create a little code and I executed a lot of times.
public static void main(String[] args) {
long ts;
String c = "sgfrt34tdfg34";
ts = System.currentTimeMillis();
for (int k = 0; k < 10000000; k++) {
c.getBytes();
}
System.out.println("t1->" + (System.currentTimeMillis() - ts));
ts = System.currentTimeMillis();
for (int i = 0; i < 10000000; i++) {
Bytes.toBytes(c);
}
System.out.println("t2->" + (System.currentTimeMillis() - ts));
}
The "second" loop is faster, so, I thought that Bytes class from hadoop was faster than the function from String class. Then, I changed the order of the loops and then c.getBytes() got faster. I executed many times, and my conclusion was, I don't know why, but something happen in my VM after the first code execute so that the results become faster for the second loop.
This is a classic java benchmarking issue. Hotspot/JIT/etc will compile your code as you use it, so it gets faster during the run.
Run around the loop at least 3000 times (10000 on a server or on 64 bit) first - then do your measurements.
You know there's something wrong, because Bytes.toBytes calls c.getBytes internally:
public static byte[] toBytes(String s) {
try {
return s.getBytes(HConstants.UTF8_ENCODING);
} catch (UnsupportedEncodingException e) {
LOG.error("UTF-8 not supported?", e);
return null;
}
}
The source is taken from here. This tells you that the call cannot possibly be faster than the direct call - at the very best (i.e. if it gets inlined) it would have the same timing. Generally, though, you'd expect it to be a little slower, because of the small overhead in calling a function.
This is the classic problem with micro-benchmarking in interpreted, garbage-collected environments with components that run at arbitrary time, such as garbage collectors. On top of that, there are hardware optimizations, such as caching, that skew the picture. As the result, the best way to see what is going on is often to look at the source.
The "second" loop is faster, so,
When you execute a method at least 10000 times, it triggers the whole method to be compiled. This means that your second loop can be
faster as it is already compiled the first time you run it.
slower because when optimised it doesn't have good information/counters on how the code is executed.
The best solution is to place each loop in a separate method so one loop doesn't optimise the other AND run this a few times, ignoring the first run.
e.g.
for(int i = 0; i < 3; i++) {
long time1 = doTest1(); // timed using System.nanoTime();
long time2 = doTest2();
System.out.printf("Test1 took %,d on average, Test2 took %,d on average%n",
time1/RUNS, time2/RUNS);
}
Most likely, the code was still compiling or not yet compiled at the time the first loop ran.
Wrap the entire method in an outer loop so you can run the benchmarks a few times, and you should see more stable results.
Read: Dynamic compilation and performance measurement.
It simply might be the case that you allocate so much space for objects with your calls to getBytes(), that the JVM Garbage Collector starts and cleans up the unused references (bringing out the trash).
Few more observations
As pointed by #dasblinkenlight above, Hadoop's Bytes.toBytes(c); internally calls the String.getBytes("UTF-8")
The variant method String.getBytes() which takes Character Set as input is faster than the one that does not take any character set. So for a given string, getBytes("UTF-8") would be faster than getBytes(). I have tested this on my machine (Windows8, JDK 7). Run the two loops one with getBytes("UTF-8") and other with getBytes() in sequence in equal iterations.
long ts;
String c = "sgfrt34tdfg34";
ts = System.currentTimeMillis();
for (int k = 0; k < 10000000; k++) {
c.getBytes("UTF-8");
}
System.out.println("t1->" + (System.currentTimeMillis() - ts));
ts = System.currentTimeMillis();
for (int i = 0; i < 10000000; i++) {
c.getBytes();
}
System.out.println("t2->" + (System.currentTimeMillis() - ts));
this gives:
t1->1970
t2->2541
and the results are same even if you change order of executions of loop. To discount any JIT optimizations, I would suggest run the tests in separate methods to confirm this (as suggested by #Peter Lawrey above)
So, Bytes.toBytes(c) should always be faster than String.getBytes()
I'm getting a very peculiar issue with my audio callbacks in my Android app (that's using NDK/OpenSL ES). I'm streaming audio output at 44.1 kHz and 512 frames (which gives me a callback time of 11.6 ms). In the callback, I'm synthesizing a couple of waveforms, filters, etc (like a synthesizer). Due to optimization I never reach over 5 ms of the callback time. However, when I turn on a specific effect (digital delay line), it starts to take a radically longer time in the callback. The digital delay line will jump from 7.5 ms (after all voices/filters have been processed) and jump up to 100 to 350 ms.
This is the most confusing part; after maybe 1 or 2 seconds, the digital delay execution time will jump from the extremely high time to 0.2 ms completion time per callback.
Why would the Android app take a long time to complete my digital delay processing code the first few callbacks and then die down to a very short and audio-happy time? I'm kind of at a loss right now and not sure how to fix this. To confirm, this only happens with the delay processing method. It's just a standard digital delay line (you can find some on github) and I feel like the algorithm isn't the problem here...
Kind of a pseudocode/rough sketch of what my audio callback code looks like:
static bool myAudioCallback(void *userData, short int *audIO, int numSamples, int srate) {
AudioData *data = (AudioData *)userData;
// Resets pointer array values to 0
for (int i = 0; i < numSamples; i++) data->buffer[i] = 0;
// Voice Generation Block
for (int voice = 0; voice < data->numVoices; voice++) {
// Reset voice buffers:
for (int i = 0; i < numSamples; i++) data->voiceBuffer[i] = 0;
// Generate Voice
data->voiceManager[voice]->generateVoiceBlock(data->voiceBuffer, numSamples);
// Sum voices
for (int i = 0; i < numSamples; i++) data->buffer[i] += data->voiceBuffer[i]];
}
// When app first starts, delayEnabled = false so user must click on a
// button on the UI to enable it.
// Trouble is that when we enable processDelay(double *buffer, in frames) the
// first time, we get a long execution time.
if (data->delayEnabled) {
data->delay->processDelay(data->buffer, numSamples);
}
// Conversion loop
for (int i = 0; i < numSamples; i++) {
double sample = clipOutput(data->buffer[i]);
audIO[2*i] = audIO[(2*i)+1] = CONV_FLT_TO_16BIT(sample * data->volume);
}
}
Thanks!
Not a great answer to the solution but this is what I did:
Before the user is able to do anything on the app, I turned on the delay and let it run its course for like 2 seconds before switching it off. This allows the callback to do its weird long 300 ms execution time while not destroying the audio.
Obviously this is not a great answer and if anyone can figure out a more logical explanation I would be more than happy to mark that as the answer.
I'm trying to compare "Cross platform mobile application development tools" vs "Android Native development" from a performance perspective. In order to do that I developed an application which makes a calculation of a serie. Below I transcript Android and Phonegap code.
Android
double serie;
long t1 = System.currentTimeMillis();
serie = 0;
for (int j = 1; j <= 5; j++) {
for (int k = 1; k <= 100000; k++) {
serie = serie + Math.log(k) / Math.log(2) + (3 * k / (2 * j)) + Math.sqrt(k) + Math.pow(k, j - 1);
}
}
long duration = System.currentTimeMillis() - t1;
Phonegap
var start = new Date().getTime();
var serie = 0;
for ( var j=1; j <= 5; j++ ){
for ( var k=1; k <= 100000; k++ ){
serie = serie + ( Math.log(k)/Math.LN2 ) + (3*k/2*j) + Math.sqrt(k) + Math.pow(k, j-1);
}
}
var end = new Date().getTime();
var duration = end - start;
Each timing was taken thirty times and the results were averaged.
Results
Android average time = 532.93ms
Phonegap average time = 230.33ms
The results are far from what I expected. I don't understand why Android performance is worse than Phonegap's. Both applications are run as release versions.
The device is a Moto G2 (Android 4.4)
Am I missing something?
I am not sure if this performance comparison makes any sense. You simply perform some computation in Java and then in JavaScript. After that, you measure computation time. It doesn't prove anything.
The only conclusion you could have is the fact that JavaScript performed this particular computation faster than Java for some reason. Maybe JavaScript optimized something under the hood. As it's dynamically typed language, you should check if Java and JavaScript code returned the same result, because I'm not sure about that. Moreover, you are measuring time in a different ways in two tests. Maybe System.currentTimeMillis(); simply takes more time than new Date().getTime(); ?
In real life, you put non-deterministic and long operations to a separate thread different than UI thread. When operation is done, you can pass the result to the UI thread. Bad project structure and bad programming practices can slow down your application. With cross-platform tools like Phonegap, you have no control over Java code and you have very limited access to low level optimization techniques and multi-threading. You also have no direct access to Android SDK.
If you really want to analyze performance, you should prepare more realistic instrumentation test. For example, create application (in two versions: Android & Phone Gap), which reads some data from a file and images from disk and then displays it on the list and with instrumentation test, you can scroll the list down to the bottom. Afterwards, you can measure time of whole instrumentation test in both cases. Having something like that, you can make some assumptions.
I developed an auto-call application. The app reads a text file that includes a phone number list and calls for a few second, ends the call and then repeats.
My problem is that the app does not send calls after 10~16 hours. I don't know the reason exactly, but I guess that the problem is the CPU usage. My app's CPU usage is almost 50%! How do I reduce CPU usage?
Here is part of source code:
if(r_count.compareTo("0")!=0) {
while(index < repeat_count) {
count = 1;
time_count = 2;
while(count < map.length) {
performDial(); //start call
reject(); //end call
finishActivity(1);
TimeDelay("60"); // wait for 60sec
count = count + 2;
time_count = time_count + 2;
onBackPressed(); // press back button for calling next number
showCallLog();
finishActivity(0);
}
index++;
}
This is the TimeDelay() method source:
public void TimeDelay(String delayTime) {
saveTime = System.currentTimeMillis()/1000;
currentTime = 0;
dTime = Integer.parseInt(delayTime);
while(currentTime - saveTime < dTime) {
currentTime = System.currentTimeMillis()/1000;
}
}
TimeDelay() repeats in the while loop for a few times.
The reason it's using 50% of your CPU is that Android apparently won't let it use 100% of the CPU, which a loop like the one in your TimeDelay() ordinarily would. (Or else you have two CPUs and it is in fact using 100% of one CPU.) What you're doing is called a busy wait and it should be obvious why continually checking a condition will use lots of CPU. So don't do that. Use Thread.sleep() instead. Your app will then use no CPU at all during the wait.
Also, for God's sake, why are you passing a string and then parseInting it, rather than just passing an Integer in the first place? :-)
If your method take a long time to finish , especially the while loop. You should put Thread.sleep(50) inside your loop. This makes you processor be able to handle other processes.
Your CPU will be reduced. Not sure but you should try.
Hope you get good result.
I have a C++ game running through JNI in Android. The frame rate varies from about 20-45fps due to scene complexity. Anything above 30fps is silly for the game; it's just burning battery. I'd like to limit the frame rate to 30 fps.
I could switch to RENDERMODE_WHEN_DIRTY, and use a Timer or ScheduledThreadPoolExecutor to requestRender(). But that adds a whole mess of extra moving parts that might or might not work consistently and correctly.
I tried injecting Thread.sleep() when things are running quickly, but this doesn't seem to work at all for small time values. And it may just be backing events into the queue anyway, not actually pausing.
Is there a "capFramerate()" method hiding in the API? Any reliable way to do this?
The solution from Mark is almost good, but not entirely correct. The problem is that the swap itself takes a considerable amount of time (especially if the video driver is caching instructions). Therefore you have to take that into account or you'll end with a lower frame rate than desired.
So the thing should be:
somewhere at the start (like the constructor):
startTime = System.currentTimeMillis();
then in the render loop:
public void onDrawFrame(GL10 gl)
{
endTime = System.currentTimeMillis();
dt = endTime - startTime;
if (dt < 33)
Thread.Sleep(33 - dt);
startTime = System.currentTimeMillis();
UpdateGame(dt);
RenderGame(gl);
}
This way you will take into account the time it takes to swap the buffers and the time to draw the frame.
When using GLSurfaceView, you perform the drawing in your Renderer's onDrawFrame which is handled in a separate thread by the GLSurfaceView. Simply make sure that each call to onDrawFrame takes (1000/[frames]) milliseconds, in your case something like 33ms.
To do this: (in your onDrawFrame)
Measure the current time before your start drawing using System.currentTimeMillis (Let's call it startTime)
Perform the drawing
Measure time again (Let's call it endTime)
deltaT = endTime - starTime
if deltaT < 33, sleep (33-deltaT)
That's it.
Fili's answer looked great to me, bad sadly limited the FPS on my Android device to 25 FPS, even though I requested 30. I figured out that Thread.sleep() works not accurately enough and sleeps longer than it should.
I found this implementation from the LWJGL project to do the job:
https://github.com/LWJGL/lwjgl/blob/master/src/java/org/lwjgl/opengl/Sync.java
Fili's solution is failing for some people, so I suspect it's sleeping until immediately after the next vsync instead of immediately before. I also feel that moving the sleep to the end of the function would give better results, because there it can pad out the current frame before the next vsync, instead of trying to compensate for the previous one. Thread.sleep() is inaccurate, but fortunately we only need it to be accurate to the nearest vsync period of 1/60s. The LWJGL code tyrondis posted a link to seems over-complicated for this situation, it's probably designed for when vsync is disabled or unavailable, which should not be the case in the context of this question.
I would try something like this:
private long lastTick = System.currentTimeMillis();
public void onDrawFrame(GL10 gl)
{
UpdateGame(dt);
RenderGame(gl);
// Subtract 10 from the desired period of 33ms to make generous
// allowance for overhead and inaccuracy; vsync will take up the slack
long nextTick = lastTick + 23;
long now;
while ((now = System.currentTimeMillis()) < nextTick)
Thread.sleep(nextTick - now);
lastTick = now;
}
If you don't want to rely on Thread.sleep, use the following
double frameStartTime = (double) System.nanoTime()/1000000;
// start time in milliseconds
// using System.currentTimeMillis() is a bad idea
// call this when you first start to draw
int frameRate = 30;
double frameInterval = (double) 1000/frame_rate;
// 1s is 1000ms, ms is millisecond
// 30 frame per seconds means one frame is 1s/30 = 1000ms/30
public void onDrawFrame(GL10 gl)
{
double endTime = (double) System.nanoTime()/1000000;
double elapsedTime = endTime - frameStartTime;
if (elapsed >= frameInterval)
{
// call GLES20.glClear(...) here
UpdateGame(elapsedTime);
RenderGame(gl);
frameStartTime += frameInterval;
}
}
You may also try and reduce the thread priority from onSurfaceCreated():
Process.setThreadPriority(Process.THREAD_PRIORITY_LESS_FAVORABLE);