Performance unterschiede Emulator und G1

  • Antworten:7
Mac Systems
  • Forum-Beiträge: 1.727

01.10.2009, 18:11:26 via Website

Hallo,

ich stelle gerade fest das meine Datenbank Inserts auf dem G1 deutlich langsamer sind als im Emulator.
Grob geschätzt um den faktor 25 unterschied. Kann Ich den Emulator dazu bewegen ebenfalls hier wie das G1 sich zu verhalten ?

thx,
Mac

— geändert am 02.10.2009, 16:51:58

Windmate HD, See you @ IO 14 , Worked on Wundercar, Glass V3, LG G Watch, Moto 360, Android TV

Antworten
Gelöschter Account
  • Forum-Beiträge: 5.136

01.10.2009, 18:21:43 via Website

Ist deine Datenbank vielleicht auf der SD - Card ? Ist die vielleicht auf dem G1 so langsam ?

Ich wüsste nicht wie man den Emulator noch langsamer machen könnte als er ohnehin schon ist.

lg
Voss

lg Voss

Antworten
Mac Systems
  • Forum-Beiträge: 1.727

01.10.2009, 18:32:47 via Website

Wie stelle Ich das fest ?

Windmate HD, See you @ IO 14 , Worked on Wundercar, Glass V3, LG G Watch, Moto 360, Android TV

Antworten
Gelöschter Account
  • Forum-Beiträge: 5.136

01.10.2009, 18:50:51 via Website

Fest macht man was mit einem Schraubenschlüssel ... :)

Scherz ohne .. Du musst doch eigentlich wissen ob Du Deine DB oder wo Du sie anlegst ... oder ?

Beim public static SQLiteDatabase openDatabase (String path, SQLiteDatabase.CursorFactory factory, int flags)

hast Du ja :

Parameters
path to database file to open and/or create
factory an optional factory class that is called to instantiate a cursor when query is called, or null for default
flags to control database access mode

Das meinte ich damit ..

Wenn Du nun bspw. eine Class 2 SD Card im Handy hast dann ist das schon recht langsam im Vergleich zu einer Class 6 Card.

lg
Voss

lg Voss

Antworten
Mac Systems
  • Forum-Beiträge: 1.727

01.10.2009, 18:58:30 via Website

Nö tue Ich nicht:

1public class Database extends SQLiteOpenHelper
2 2{
3 3
4 4 private final static String LOG_TAG = Database.class.getSimpleName();
5 5
6 6 final static String DATABASE_NAME = "windroid.db";
7 7 final static int VERSION = 20;
8 8
9 9 final List<String> createScripts;
1010
1111 /**
1212 *
1313 * @param context
1414 */
1515 public Database(final Context context)
1616 {
1717 super(context, DATABASE_NAME, null, VERSION);


kA welche Karte ich da habe, ist die standart SD Karte die im Karton war :blink: Class 6 oder so würde ich auch eher in meine EOS stecken wo bei Serienaufnahmen ernsthaft Daten anfallen. als in so nen "Popelhandy" (Ich hoffe ihr entschuldigt das *g).

- Mac

— geändert am 01.10.2009, 18:58:52

Windmate HD, See you @ IO 14 , Worked on Wundercar, Glass V3, LG G Watch, Moto 360, Android TV

Antworten
Mac Systems
  • Forum-Beiträge: 1.727

01.10.2009, 19:00:09 via Website

PS. Über diese dämliche Vorschau die alle Code Formatierungen zerschiesst muss Ich mich wohl bis zum Sanktnimmerleinstag aufregen ? :angry:

Windmate HD, See you @ IO 14 , Worked on Wundercar, Glass V3, LG G Watch, Moto 360, Android TV

Antworten
Gelöschter Account
  • Forum-Beiträge: 5.136

01.10.2009, 19:15:34 via Website

Probiers mal mit

final String getPath(), Getter for the path to the database file.

voss

lg Voss

Antworten
Mac Systems
  • Forum-Beiträge: 1.727

02.10.2009, 16:37:50 via Website

So,

die Nacht hat sich gelohnt :D

Ich bin gestern so gegen 19:00 Uhr zum Sport, auf dem G1 liefen die Inserts weiter. Gegen 23:00 Uhr habe Ich wieder auf das Telefon geschaut, er machte Lustig weiter. Ups dachte Ich diese Geschwindigkeit hat Showstopper Qualität.

Danach habe Ich mir nochmals den "Insert Loop" angeschaut und nach "Performance Sünden" gesucht.



Lange rede kurzer Sinn, hier der Loop wie er vorher war:

1public void update()
2 {
3 clearAllSpots();
4 final SQLiteDatabase db = database.getWritableDatabase();
5 final SQLiteStatement insertSpotStatement = db.compileStatement(INSERT_SPOT);
6 final SQLiteStatement insertContinentStatement = db.compileStatement(INSERT_CONTINENT);
7 // db.beginTransaction();
8
9 Log.d(LOG_TAG, "executeInsert");
10
11 final long start = System.currentTimeMillis();
12 try
13 {
14 for (final Continent continent : Continent.values())
15 {
16 updateContinentTable(insertContinentStatement, continent);
17 insertContinentStatement.execute();
18
19 final Country[] countrys = continent.getCoutrys();
20 for (final Country country : countrys)
21 {
22 final Region[] regions = country.getRegions();
23 for (final Region region : regions)
24 {
25 final Station[] stations = region.getStations();
26 for (final Station station : stations)
27 {
28 /**
29 * "INSERT_SPOT INTO spot (spotid,continentid,regionid,name,keyword,superforecast,forecast,statistic,wavereport,waveforecast) "
30 * values (?,?,?,?,?,?,?,?,?,?);";
31 */
32 updateSpotTable(insertSpotStatement, continent, region, station);
33 insertSpotStatement.execute();
34
35 }
36 }
37 }
38 }
39 }
40 finally
41 {
42 // db.endTransaction();
43 insertSpotStatement.close();
44 IOUtils.close(db);
45 final long time = System.currentTimeMillis() - start;
46 Log.d(LOG_TAG, "Insert took " + time + " ms");
47 }


Zuerst habe Ich die insertXXX Methoden final static gesetzt, was wenig brachte, diese sahen vorher in etwa so aus:

1/**
2 * @param insertStatement
3 * @param continent
4 * @param region
5 * @param station
6 */
7 private void updateContinentTable(final SQLiteStatement insertStatement, final Continent continent)
8 {
9 insertStatement.bindString(1, continent.getId());
10 insertStatement.bindString(2, continent.name());
11 }


Dann fing Ich an den Innerloop zu optimieren, indem Ich die Methode updateSpotTable in den loop verschob. Der Performancegewinn war nicht messbar.

Interessanter waren da schon die Business Objekte Station, Region, Country und deren getXXXX Methoden:

1public Region[] getRegions()
2 {
3 return regions.toArray(new Region[regions.size()]);
4 }

Ich denke dazu muss man nicht so viel sagen, hier wird viel Garbage erzeugt, auch wenn es nach Lehrbuch ist.
Intern halte Ich ein Set in diesen Objekten Set<Region>, also habe Ich den Objekten eine iterator Methode spendiert:

1public Iterator<Region> iterator()
2 {
3 return regions.iterator();
4 }

Und die insert schleifen entsprechend angepasst. Dann fühlte ich erstmals einen Performancegewinn. Allerdings war das immer noch nicht gut genug.

Ich habe während der Inserts einen ProgressDialog laufen (das ist oben nicht zu sehen), dieser wird im Innerloop updated, daher habe Ich das einfach mal nicht getan. Ohh Wunder,im Emulator rannte das recht schnell also sollte es auf dem echten Gerät ebenfalls deutlich schneller gehen (Der Emulator ist wirklich nur einen wage Annäherung an die Geschwindigkeit des G1).

Auf dem echten G1 lief der Datenbank Insert nun deutlichst schneller, in ca. 1 Minute waren alle Datensätze eingearbeitet.
Nun ging es darum dem User dennoch etwas an Feedback zu geben damit er nicht denkt die Anwendung ist "abgeschmiert".

Daher ist im innerloop der Code folgendermassen verändert worden:

1while (stations.hasNext())
2 {
3 updateSpotTable(insertSpotStatement, continent, country, region, stations.next());
4 index++;
5 if (index % 100 == 0)
6 {
7 progress.incrementProgressBy(100);
8 }
9 }


Die Performance ist nun auf einem Level der als brauchbar anzusehen ist auf meinem G1. Ich habe also folgendes feststellen können: UI Update sollte man auf ein minimum reduzieren wenn möglich und nebenbei drauf achten das der GC nicht zuviel futter bekommt.

Der Performancegewinn ist mehr als beachtlich, da es anfangs mehrere Stunden dauerte, so das die App den Fokus verliert und auch weniger CPU Zyklen bereitgestellt bekommt was das ganze noch langsamer werden lässt.
Ich denke das Hauptproblem liegt darin das das UI zu oft zu refreshed wurde und dadurch das System mit Events zu "geflutet" wurde. Ähnliches kenne Ich aus Swing, nur das es hier schneller auftritt.

Hier nochmals das Endergebnis:

1public void update()
2 {
3 clearAllSpots();
4 final SQLiteDatabase db = database.getWritableDatabase();
5 final SQLiteStatement insertSpotStatement = db.compileStatement(INSERT_SPOT);
6 final SQLiteStatement insertContinentStatement = db.compileStatement(INSERT_CONTINENT);
7 final SQLiteStatement insertCountryStatement = db.compileStatement(INSERT_COUNTRY);
8 final SQLiteStatement insertRegionStatement = db.compileStatement(INSERT_REGION);
9
10 // db.beginTransaction();
11
12 if (!Continent.isParsed())
13 {
14 throw new IllegalStateException("Please parse Continents");
15 }
16
17 Log.d(LOG_TAG, "executeInsert");
18
19 final long start = System.currentTimeMillis();
20 int index = 0;
21 try
22 {
23 for (final Continent continent : Continent.values())
24 {
25 updateContinentTable(insertContinentStatement, continent);
26 insertContinentStatement.executeInsert();
27
28 final Iterator<Country> countrys = continent.iterator();
29 while (countrys.hasNext())
30 {
31 final Country country = countrys.next();
32 updateCountryTable(insertCountryStatement, country);
33 insertCountryStatement.executeInsert();
34
35 final Iterator<Region> regions = country.iterator();
36 while (regions.hasNext())
37 {
38 final Region region = regions.next();
39 updateRegionTable(insertRegionStatement, region);
40 insertRegionStatement.executeInsert();
41
42 final Iterator<Station> stations = region.iterator();
43 while (stations.hasNext())
44 {
45 updateSpotTable(insertSpotStatement, continent, country, region, stations.next());
46 index++;
47 if (index % 100 == 0)
48 {
49 progress.incrementBy(100);
50 }
51 }
52 }
53 }
54 }
55 }
56 finally
57 {
58 // db.endTransaction();
59 insertSpotStatement.close();
60 insertCountryStatement.close();
61 insertRegionStatement.close();
62 insertContinentStatement.close();
63
64 IOUtils.close(db);
65 final long time = System.currentTimeMillis() - start;
66 Log.d(LOG_TAG, "Insert took " + time + " ms");
67 }
68
69 }


Hoffe das hilft jemanden weiter,
Mac

PS: Nebenbei konnte Ich keine Unterschiede feststellen wenn Ich indiezies auf den Tabellen habe bei der Einarbeitung

Windmate HD, See you @ IO 14 , Worked on Wundercar, Glass V3, LG G Watch, Moto 360, Android TV

Antworten