Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor: Performance tune for OASIS service #353

Merged
merged 11 commits into from
May 28, 2020
Merged
1 change: 1 addition & 0 deletions CHANGELOG-FORK.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ Changes from v10.3.0
- CHANGED for integration of pre-generated connectivity data with OASIS service [#339](https://github.com/Telenav/osrm-backend/pull/339)
- CHANGED for internal refactoring, replace `Location` in `spatialindexer` to nav.Location, replace all name of `point` to `place` [#341](https://github.com/Telenav/osrm-backend/pull/341)
- CHANGED for internal refactoring, move package oasis/solution, oasis/osrmhelper and oasis/searchhelper into oasis/internal [#343](https://github.com/Telenav/osrm-backend/pull/343)
- CHANGED for internal refactoring, improve performance for OASIS service, more information please go to [#344](https://github.com/Telenav/osrm-backend/issues/344) [#353](https://github.com/Telenav/osrm-backend/pull/353)
- Bugfix:
- Performance:
- Tools:
Expand Down
2 changes: 2 additions & 0 deletions integration/cmd/oasis/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ var flags struct {
tnSearchAPIKey string
tnSearchAPISignature string
localDataPath string
cpuProfileFile string
}

func init() {
Expand All @@ -23,4 +24,5 @@ func init() {
flag.StringVar(&flags.tnSearchAPIKey, "searchApiKey", "", "API key for TN-Search-backend")
flag.StringVar(&flags.tnSearchAPISignature, "searchApiSignature", "", "API Signature for TN-Search-backend")
flag.StringVar(&flags.localDataPath, "datapath", "", "Local data path for index data")
flag.StringVar(&flags.cpuProfileFile, "cpuprofile", "", "write cpu profile to `file`")
}
15 changes: 15 additions & 0 deletions integration/cmd/oasis/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ package main

import (
"flag"
"log"
"net/http"
"os"
"runtime/pprof"
"strconv"

"github.com/Telenav/osrm-backend/integration/util/appversion"
Expand All @@ -16,6 +19,18 @@ func main() {
appversion.PrintExit()
defer glog.Flush()

if flags.cpuProfileFile != "" {
f, err := os.Create(flags.cpuProfileFile)
if err != nil {
log.Fatal("could not create CPU profile: ", err)
}
defer f.Close() // error handling omitted for example
if err := pprof.StartCPUProfile(f); err != nil {
log.Fatal("could not start CPU profile: ", err)
}
defer pprof.StopCPUProfile()
}

mux := http.NewServeMux()

oasisService, err := oasis.New(flags.osrmBackendEndpoint, flags.finderType, flags.tnSearchEndpoint,
Expand Down
110 changes: 70 additions & 40 deletions integration/service/oasis/chargingstrategy/fake_charge_strategy.go
Original file line number Diff line number Diff line change
@@ -1,91 +1,121 @@
package chargingstrategy

import (
"math"

"github.com/Telenav/osrm-backend/integration/util"
"github.com/golang/glog"
)

type fakeChargeStrategy struct {
maxEnergyLevel float64
maxEnergyLevel float64
sixtyPercentOFMaxEnergy float64
eightyPercentOfMaxEnergy float64
costFrom60PercentTo80Percent float64
costFrom60PercentTo100Percent float64
costFrom80PercentTo100Percent float64
stateCandidates []State
}

// NewFakeChargingStrategy creates fake charge strategy
func NewFakeChargingStrategy(maxEnergyLevel float64) *fakeChargeStrategy {
sixtyPercentOFMaxEnergy := math.Round(maxEnergyLevel*0.6*100) / 100
eightyPercentOfMaxEnergy := math.Round(maxEnergyLevel*0.8*100) / 100
maxEnergyLevel = math.Round(maxEnergyLevel*100) / 100
costFrom60PercentTo80Percent := 3600.0
costFrom60PercentTo100Percent := 10800.0
costFrom80PercentTo100Percent := 7200.0
stateCandidates := []State{
{
Energy: sixtyPercentOFMaxEnergy,
},
{
Energy: eightyPercentOfMaxEnergy,
},
{
Energy: maxEnergyLevel,
},
}

return &fakeChargeStrategy{
maxEnergyLevel: maxEnergyLevel,
maxEnergyLevel: maxEnergyLevel,
sixtyPercentOFMaxEnergy: sixtyPercentOFMaxEnergy,
eightyPercentOfMaxEnergy: eightyPercentOfMaxEnergy,
costFrom60PercentTo80Percent: costFrom60PercentTo80Percent,
costFrom60PercentTo100Percent: costFrom60PercentTo100Percent,
costFrom80PercentTo100Percent: costFrom80PercentTo100Percent,
stateCandidates: stateCandidates,
}
}

// @todo:
// - Influence of returning candidate with no charge time and additional energy
// CreateChargingStates returns different charging strategy
func (f *fakeChargeStrategy) CreateChargingStates() []State {
return []State{
State{
Energy: f.maxEnergyLevel * 0.6,
},
State{
Energy: f.maxEnergyLevel * 0.8,
},
State{
Energy: f.maxEnergyLevel,
},
}
return f.stateCandidates
}

var zeroChargeCost = ChargingCost{
Duration: 0.0,
}

// Fake charge strategy
// From empty energy:
// 1 hour charge to 60% of max energy
// 2 hour charge to 80%, means from 60% ~ 80% need 1 hour
// 4 hour charge to 100%, means from 80% ~ 100% need 2 hours
// charge rule #1: 1 hour charge to 60% of max energy
// charge rule #2: 2 hour charge to 80%, means from 60% ~ 80% need 1 hour
// charge rule #3: 4 hour charge to 100%, means from 80% ~ 100% need 2 hours
func (f *fakeChargeStrategy) EvaluateCost(arrivalEnergy float64, targetState State) ChargingCost {
sixtyPercentOfMaxEnergy := f.maxEnergyLevel * 0.6
eightyPercentOfMaxEnergy := f.maxEnergyLevel * 0.8
noNeedCharge := ChargingCost{
Duration: 0.0,
}
sixtyPercentOfMaxEnergy := f.sixtyPercentOFMaxEnergy
eightyPercentOfMaxEnergy := f.eightyPercentOfMaxEnergy

if arrivalEnergy > targetState.Energy ||
util.Float64Equal(targetState.Energy, 0.0) {
return noNeedCharge
return zeroChargeCost
}

totalTime := 0.0
currentEnergy := arrivalEnergy

if arrivalEnergy < sixtyPercentOfMaxEnergy {
energyNeeded4Stage1 := sixtyPercentOfMaxEnergy - arrivalEnergy
totalTime += energyNeeded4Stage1 / sixtyPercentOfMaxEnergy * 3600.0
currentEnergy = sixtyPercentOfMaxEnergy
}

if util.Float64Equal(targetState.Energy, sixtyPercentOfMaxEnergy) {
if util.Float64Equal(targetState.Energy, sixtyPercentOfMaxEnergy) {
return ChargingCost{
Duration: totalTime,
}
} else if util.Float64Equal(targetState.Energy, eightyPercentOfMaxEnergy) {
return ChargingCost{
Duration: totalTime + f.costFrom60PercentTo80Percent,
}
}
return ChargingCost{
Duration: totalTime,
Duration: totalTime + f.costFrom60PercentTo100Percent,
}
}

if arrivalEnergy < eightyPercentOfMaxEnergy {
energyNeeded4Stage2 := eightyPercentOfMaxEnergy - currentEnergy
energyNeeded4Stage2 := eightyPercentOfMaxEnergy - arrivalEnergy
totalTime += energyNeeded4Stage2 / (eightyPercentOfMaxEnergy - sixtyPercentOfMaxEnergy) * 3600.0
currentEnergy = eightyPercentOfMaxEnergy
}
if util.Float64Equal(targetState.Energy, eightyPercentOfMaxEnergy) {

if util.Float64Equal(targetState.Energy, eightyPercentOfMaxEnergy) {
return ChargingCost{
Duration: totalTime,
}
}
return ChargingCost{
Duration: totalTime,
Duration: totalTime + f.costFrom80PercentTo100Percent,
}
}

if arrivalEnergy < f.maxEnergyLevel {
energyNeeded4Stage3 := f.maxEnergyLevel - currentEnergy
energyNeeded4Stage3 := f.maxEnergyLevel - arrivalEnergy
totalTime += energyNeeded4Stage3 / (f.maxEnergyLevel - eightyPercentOfMaxEnergy) * 7200.0
}

if util.Float64Equal(targetState.Energy, f.maxEnergyLevel) {
return ChargingCost{
Duration: totalTime,
if util.Float64Equal(targetState.Energy, f.maxEnergyLevel) {
return ChargingCost{
Duration: totalTime,
}
}
}

glog.Fatalf("Invalid charging state %#v\n", targetState)
return noNeedCharge
return zeroChargeCost
}
47 changes: 11 additions & 36 deletions integration/service/oasis/connectivitymap/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package connectivitymap
import (
"sync"

"github.com/Telenav/osrm-backend/integration/service/oasis/internal/common"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still common? Aha

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will change it to domain/entity :)

"github.com/Telenav/osrm-backend/integration/service/oasis/spatialindexer"
"github.com/golang/glog"
)
Expand Down Expand Up @@ -73,34 +74,18 @@ func (builder *connectivityMapBuilder) process() {
glog.Infof("builder's process is finished, start number of %d workers.\n", builder.numOfWorker)
}

func (builder *connectivityMapBuilder) work(workerID int, source <-chan spatialindexer.PlaceInfo, sink chan<- placeIDWithNearByPlaceIDs) {
func (builder *connectivityMapBuilder) work(workerID int, source <-chan common.PlaceInfo, sink chan<- placeIDWithNearByPlaceIDs) {
defer builder.workerWaitGroup.Done()

counter := 0
for p := range source {
counter += 1
nearbyIDs := builder.finder.FindNearByPlaceIDs(p.Location, builder.distanceLimit, spatialindexer.UnlimitedCount)
rankedResults := builder.ranker.RankPlaceIDsByShortestDistance(p.Location, nearbyIDs)

ids := make([]IDAndWeight, 0, len(rankedResults))
for _, r := range rankedResults {
// skip connectivity to itself
if r.ID == p.ID {
continue
}

ids = append(ids, IDAndWeight{
ID: r.ID,
Weight: Weight{
Distance: r.Distance,
Duration: r.Duration,
},
})
}
nearbyIDs := builder.finder.FindNearByPlaceIDs(*p.Location, builder.distanceLimit, spatialindexer.UnlimitedCount)
rankedResults := builder.ranker.RankPlaceIDsByShortestDistance(*p.Location, nearbyIDs)

sink <- placeIDWithNearByPlaceIDs{
id: p.ID,
ids: ids,
ids: rankedResults,
}
}

Expand Down Expand Up @@ -129,8 +114,8 @@ func (builder *connectivityMapBuilder) wait() {
}

type placeIDWithNearByPlaceIDs struct {
id spatialindexer.PlaceID
ids []IDAndWeight
id common.PlaceID
ids []*common.RankedPlaceInfo
}

func (builder *connectivityMapBuilder) buildInSerial() ID2NearByIDsMap {
Expand All @@ -140,22 +125,12 @@ func (builder *connectivityMapBuilder) buildInSerial() ID2NearByIDsMap {

go func() {
for p := range builder.iterator.IteratePlaces() {
nearbyIDs := builder.finder.FindNearByPlaceIDs(p.Location, builder.distanceLimit, spatialindexer.UnlimitedCount)
rankedResults := builder.ranker.RankPlaceIDsByGreatCircleDistance(p.Location, nearbyIDs)

ids := make([]IDAndWeight, 0, len(rankedResults))
for _, r := range rankedResults {
ids = append(ids, IDAndWeight{
ID: r.ID,
Weight: Weight{
Distance: r.Distance,
Duration: r.Duration,
},
})
}
nearbyIDs := builder.finder.FindNearByPlaceIDs(*p.Location, builder.distanceLimit, spatialindexer.UnlimitedCount)
rankedResults := builder.ranker.RankPlaceIDsByGreatCircleDistance(*p.Location, nearbyIDs)

internalResult <- placeIDWithNearByPlaceIDs{
id: p.ID,
ids: ids,
ids: rankedResults,
}
}
close(internalResult)
Expand Down
Loading