Bug 1369604: Use HighlightCandidateCursorIndices to cache. r=liuche

This reduces the calls to `getColumnIndexOrThrow` to 9 (from 1.6k) and
HighlightsRanking.extractFeatures goes from 77.1% inclusive CPU time -> 40.8%,
14.6k ms -> 7.1k ms.

MozReview-Commit-ID: L6HqvBK5I4i

--HG--
extra : rebase_source : f67c5ed207a4684edc4a3e7779dabd59c7f98608
This commit is contained in:
Michael Comella 2017-07-24 18:12:05 -07:00
Родитель a764197b83
Коммит 9c75c2a05e
7 изменённых файлов: 81 добавлений и 36 удалений

Просмотреть файл

@ -6,8 +6,7 @@
package org.mozilla.gecko.activitystream;
import android.database.Cursor;
import org.mozilla.gecko.db.BrowserContract;
import org.mozilla.gecko.activitystream.ranking.HighlightCandidateCursorIndices;
/**
* Various util methods and constants that are shared by different parts of Activity Stream.
@ -18,12 +17,12 @@ public class Utils {
BOOKMARKED
}
public static HighlightSource highlightSource(final Cursor cursor) {
if (-1 != cursor.getLong(cursor.getColumnIndexOrThrow(BrowserContract.Highlights.BOOKMARK_ID))) {
public static HighlightSource highlightSource(final Cursor cursor, final HighlightCandidateCursorIndices cursorIndices) {
if (-1 != cursor.getLong(cursorIndices.bookmarkIDColumnIndex)) {
return HighlightSource.BOOKMARKED;
}
if (-1 != cursor.getLong(cursor.getColumnIndexOrThrow(BrowserContract.Highlights.HISTORY_ID))) {
if (-1 != cursor.getLong(cursorIndices.historyIDColumnIndex)) {
return HighlightSource.VISITED;
}

Просмотреть файл

@ -8,9 +8,8 @@ package org.mozilla.gecko.activitystream.homepanel.model;
import android.database.Cursor;
import android.support.annotation.Nullable;
import android.text.format.DateUtils;
import org.mozilla.gecko.activitystream.Utils;
import org.mozilla.gecko.db.BrowserContract;
import org.mozilla.gecko.activitystream.ranking.HighlightCandidateCursorIndices;
public class Highlight implements Item {
private final String title;
@ -25,19 +24,19 @@ public class Highlight implements Item {
private @Nullable Boolean isPinned;
private @Nullable Boolean isBookmarked;
public static Highlight fromCursor(Cursor cursor) {
return new Highlight(cursor);
public static Highlight fromCursor(final Cursor cursor, final HighlightCandidateCursorIndices cursorIndices) {
return new Highlight(cursor, cursorIndices);
}
private Highlight(Cursor cursor) {
title = cursor.getString(cursor.getColumnIndexOrThrow(BrowserContract.History.TITLE));
url = cursor.getString(cursor.getColumnIndexOrThrow(BrowserContract.Combined.URL));
source = Utils.highlightSource(cursor);
time = cursor.getLong(cursor.getColumnIndexOrThrow(BrowserContract.Highlights.DATE));
private Highlight(final Cursor cursor, final HighlightCandidateCursorIndices cursorIndices) {
title = cursor.getString(cursorIndices.titleColumnIndex);
url = cursor.getString(cursorIndices.urlColumnIndex);
source = Utils.highlightSource(cursor, cursorIndices);
time = cursor.getLong(cursorIndices.highlightsDateColumnIndex);
historyId = cursor.getLong(cursor.getColumnIndexOrThrow(BrowserContract.Highlights.HISTORY_ID));
historyId = cursor.getLong(cursorIndices.historyIDColumnIndex);
metadata = Metadata.fromCursor(cursor);
metadata = Metadata.fromCursor(cursor, cursorIndices);
updateState();
}

Просмотреть файл

@ -8,17 +8,15 @@ package org.mozilla.gecko.activitystream.homepanel.model;
import android.database.Cursor;
import android.text.TextUtils;
import android.util.Log;
import org.json.JSONException;
import org.json.JSONObject;
import org.mozilla.gecko.db.BrowserContract;
import org.mozilla.gecko.activitystream.ranking.HighlightCandidateCursorIndices;
public class Metadata {
private static final String LOGTAG = "GeckoMetadata";
public static Metadata fromCursor(Cursor cursor) {
return new Metadata(
cursor.getString(cursor.getColumnIndexOrThrow(BrowserContract.Highlights.METADATA)));
public static Metadata fromCursor(final Cursor cursor, final HighlightCandidateCursorIndices cursorIndices) {
return new Metadata(cursor.getString(cursorIndices.metadataColumnIndex));
}
private String provider;

Просмотреть файл

@ -12,7 +12,6 @@ import android.support.annotation.StringDef;
import android.support.annotation.VisibleForTesting;
import org.mozilla.gecko.activitystream.ranking.RankingUtils.Func1;
import org.mozilla.gecko.db.BrowserContract;
import org.mozilla.gecko.activitystream.homepanel.model.Highlight;
import java.util.HashMap;
@ -44,11 +43,12 @@ import java.util.Map;
private String host;
private double score;
public static HighlightCandidate fromCursor(Cursor cursor) throws InvalidHighlightCandidateException {
public static HighlightCandidate fromCursor(final Cursor cursor, final HighlightCandidateCursorIndices cursorIndices)
throws InvalidHighlightCandidateException {
final HighlightCandidate candidate = new HighlightCandidate();
extractHighlight(candidate, cursor);
extractFeatures(candidate, cursor);
extractHighlight(candidate, cursor, cursorIndices);
extractFeatures(candidate, cursor, cursorIndices);
return candidate;
}
@ -56,22 +56,24 @@ import java.util.Map;
/**
* Extract highlight object from cursor.
*/
private static void extractHighlight(HighlightCandidate candidate, Cursor cursor) {
candidate.highlight = Highlight.fromCursor(cursor);
private static void extractHighlight(final HighlightCandidate candidate, final Cursor cursor,
final HighlightCandidateCursorIndices cursorIndices) {
candidate.highlight = Highlight.fromCursor(cursor, cursorIndices);
}
/**
* Extract and assign features that will be used for ranking.
*/
private static void extractFeatures(HighlightCandidate candidate, Cursor cursor) throws InvalidHighlightCandidateException {
private static void extractFeatures(final HighlightCandidate candidate, final Cursor cursor,
final HighlightCandidateCursorIndices cursorIndices) throws InvalidHighlightCandidateException {
candidate.features.put(
FEATURE_AGE_IN_DAYS,
(System.currentTimeMillis() - cursor.getDouble(cursor.getColumnIndexOrThrow(BrowserContract.History.DATE_LAST_VISITED)))
(System.currentTimeMillis() - cursor.getDouble(cursorIndices.historyDateLastVisitedColumnIndex))
/ (1000 * 3600 * 24));
candidate.features.put(
FEATURE_VISITS_COUNT,
cursor.getDouble(cursor.getColumnIndexOrThrow(BrowserContract.History.VISITS)));
cursor.getDouble(cursorIndices.visitsColumnIndex));
// Until we can determine those numbers we assume this domain has only been visited once
// and the cursor returned all database entries.
@ -108,15 +110,14 @@ import java.util.Map;
// to the real creation date, or the earliest one mentioned in the clients constellation.
// We are sourcing highlights from the recent visited history - so in order to
// show up this bookmark need to have been visited recently too.
final int bookmarkDateColumnIndex = cursor.getColumnIndexOrThrow(BrowserContract.Bookmarks.DATE_CREATED);
if (cursor.isNull(bookmarkDateColumnIndex)) {
if (cursor.isNull(cursorIndices.bookmarkDateCreatedColumnIndex)) {
candidate.features.put(
FEATURE_BOOKMARK_AGE_IN_MILLISECONDS,
0d);
} else {
candidate.features.put(
FEATURE_BOOKMARK_AGE_IN_MILLISECONDS,
Math.max(1, System.currentTimeMillis() - cursor.getDouble(bookmarkDateColumnIndex)));
Math.max(1, System.currentTimeMillis() - cursor.getDouble(cursorIndices.bookmarkDateCreatedColumnIndex)));
}
candidate.features.put(

Просмотреть файл

@ -0,0 +1,45 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.gecko.activitystream.ranking;
import android.database.Cursor;
import org.mozilla.gecko.db.BrowserContract;
/**
* A cache of the column indices of the given Cursor.
*
* We use this for performance reasons: {@link Cursor#getColumnIndexOrThrow(String)} will do a HashMap look-up and
* String comparison each time it's called, which gets expensive while iterating through HighlightCandidate results
* (currently a maximum of 500 items), so we cache the values.
*/
public class HighlightCandidateCursorIndices {
public final int titleColumnIndex;
public final int urlColumnIndex;
public final int visitsColumnIndex;
public final int metadataColumnIndex;
public final int highlightsDateColumnIndex;
public final int bookmarkDateCreatedColumnIndex;
public final int historyDateLastVisitedColumnIndex;
public final int historyIDColumnIndex;
public final int bookmarkIDColumnIndex;
HighlightCandidateCursorIndices(final Cursor cursor) {
titleColumnIndex = cursor.getColumnIndexOrThrow(BrowserContract.History.TITLE);
urlColumnIndex = cursor.getColumnIndexOrThrow(BrowserContract.Combined.URL);
visitsColumnIndex = cursor.getColumnIndexOrThrow(BrowserContract.History.VISITS);
metadataColumnIndex = cursor.getColumnIndexOrThrow(BrowserContract.Highlights.METADATA);
highlightsDateColumnIndex = cursor.getColumnIndexOrThrow(BrowserContract.Highlights.DATE);
bookmarkDateCreatedColumnIndex = cursor.getColumnIndexOrThrow(BrowserContract.Bookmarks.DATE_CREATED);
historyDateLastVisitedColumnIndex = cursor.getColumnIndexOrThrow(BrowserContract.History.DATE_LAST_VISITED);
historyIDColumnIndex = cursor.getColumnIndexOrThrow(BrowserContract.Highlights.HISTORY_ID);
bookmarkIDColumnIndex = cursor.getColumnIndexOrThrow(BrowserContract.Highlights.BOOKMARK_ID);
}
}

Просмотреть файл

@ -7,8 +7,8 @@ package org.mozilla.gecko.activitystream.ranking;
import android.database.Cursor;
import android.support.annotation.VisibleForTesting;
import android.util.Log;
import android.util.Log;
import org.mozilla.gecko.activitystream.homepanel.model.Highlight;
import java.util.Arrays;
@ -96,12 +96,14 @@ public class HighlightsRanking {
* Extract features for every candidate. The heavy lifting is done in
* HighlightCandidate.fromCursor().
*/
@VisibleForTesting static List<HighlightCandidate> extractFeatures(Cursor cursor) {
@VisibleForTesting static List<HighlightCandidate> extractFeatures(final Cursor cursor) {
// Cache column indices for performance: see class Javadoc for more info.
final HighlightCandidateCursorIndices cursorIndices = new HighlightCandidateCursorIndices(cursor);
return looselyMapCursor(cursor, new Func1<Cursor, HighlightCandidate>() {
@Override
public HighlightCandidate call(Cursor cursor) {
try {
return HighlightCandidate.fromCursor(cursor);
return HighlightCandidate.fromCursor(cursor, cursorIndices);
} catch (HighlightCandidate.InvalidHighlightCandidateException e) {
Log.w(LOG_TAG, "Skipping invalid highlight item", e);
return null;

Просмотреть файл

@ -525,6 +525,7 @@ gbjar.sources += ['java/org/mozilla/gecko/' + x for x in [
'activitystream/homepanel/topsites/TopSitesPageAdapter.java',
'activitystream/homepanel/topsites/TopSitesPagerAdapter.java',
'activitystream/ranking/HighlightCandidate.java',
'activitystream/ranking/HighlightCandidateCursorIndices.java',
'activitystream/ranking/HighlightsRanking.java',
'activitystream/ranking/RankingUtils.java',
'activitystream/Utils.java',