open-match.dev/open-match@v1.8.1/examples/scale/scenarios/scenarios.go (about) 1 // Copyright 2019 Google LLC 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package scenarios 16 17 import ( 18 "sync" 19 20 "github.com/sirupsen/logrus" 21 "google.golang.org/grpc" 22 "open-match.dev/open-match/examples/scale/scenarios/backfill" 23 "open-match.dev/open-match/examples/scale/scenarios/firstmatch" 24 "open-match.dev/open-match/internal/util/testing" 25 "open-match.dev/open-match/pkg/matchfunction" 26 "open-match.dev/open-match/pkg/pb" 27 ) 28 29 var ( 30 queryServiceAddress = "open-match-query.open-match.svc.cluster.local:50503" // Address of the QueryService Endpoint. 31 32 logger = logrus.WithFields(logrus.Fields{ 33 "app": "scale", 34 }) 35 ) 36 37 // GameScenario defines what tickets look like, and how they should be matched. 38 type GameScenario interface { 39 // Ticket creates a new ticket, with randomized parameters. 40 Ticket() *pb.Ticket 41 42 // Backfill creates a new backfill, with randomized parameters. 43 Backfill() *pb.Backfill 44 45 // Profiles lists all of the profiles that should run. 46 Profiles() []*pb.MatchProfile 47 48 // MatchFunction is the custom logic implementation of the match function. 49 MatchFunction(p *pb.MatchProfile, poolBackfills map[string][]*pb.Backfill, poolTickets map[string][]*pb.Ticket) ([]*pb.Match, error) 50 51 // Evaluate is the custom logic implementation of the evaluator. 52 Evaluate(stream pb.Evaluator_EvaluateServer) error 53 } 54 55 // ActiveScenario sets the scenario with preset parameters that we want to use for current Open Match benchmark run. 56 var ActiveScenario = func() *Scenario { 57 var gs GameScenario = firstmatch.Scenario() 58 59 // TODO: Select which scenario to use based on some configuration or choice, 60 // so it's easier to run different scenarios without changing code. 61 //gs = battleroyal.Scenario() 62 //gs = teamshooter.Scenario() 63 s := backfill.Scenario() 64 gs = s 65 66 return &Scenario{ 67 FrontendTotalTicketsToCreate: -1, 68 FrontendTicketCreatedQPS: 100, 69 FrontendCreatesBackfillsOnStart: true, 70 FrontendTotalBackfillsToCreate: 1000, 71 FrontendDeletesTickets: true, 72 73 BackendAssignsTickets: false, 74 BackendAcknowledgesBackfills: true, 75 BackendDeletesBackfills: true, 76 77 Ticket: gs.Ticket, 78 Backfill: gs.Backfill, 79 BackfillDeleteCond: s.BackfillDeleteCond, 80 Profiles: gs.Profiles, 81 82 MMF: queryPoolsWrapper(gs.MatchFunction), 83 Evaluator: gs.Evaluate, 84 } 85 }() 86 87 // Scenario defines the controllable fields for Open Match benchmark scenarios 88 type Scenario struct { 89 // TODO: supports the following controllable parameters 90 91 // MatchFunction Configs 92 // MatchOverlapRatio float32 93 // TicketSearchFieldsUnitSize int 94 // TicketSearchFieldsNumber int 95 96 // GameFrontend Configs 97 // TicketExtensionSize int 98 // PendingTicketNumber int 99 // MatchExtensionSize int 100 FrontendTicketCreatedQPS uint32 101 FrontendTotalTicketsToCreate int // TotalTicketsToCreate = -1 let scale-frontend create tickets forever 102 FrontendTotalBackfillsToCreate int 103 FrontendCreatesBackfillsOnStart bool 104 FrontendDeletesTickets bool 105 106 // GameBackend Configs 107 // ProfileNumber int 108 // FilterNumber int 109 BackendAssignsTickets bool 110 BackendAcknowledgesBackfills bool 111 BackendDeletesBackfills bool 112 113 Ticket func() *pb.Ticket 114 Backfill func() *pb.Backfill 115 BackfillDeleteCond func(*pb.Backfill) bool 116 Profiles func() []*pb.MatchProfile 117 118 MMF matchFunction 119 Evaluator evaluatorFunction 120 } 121 122 type matchFunction func(*pb.RunRequest, pb.MatchFunction_RunServer) error 123 type evaluatorFunction func(pb.Evaluator_EvaluateServer) error 124 125 func (mmf matchFunction) Run(req *pb.RunRequest, srv pb.MatchFunction_RunServer) error { 126 return mmf(req, srv) 127 } 128 129 func (eval evaluatorFunction) Evaluate(srv pb.Evaluator_EvaluateServer) error { 130 return eval(srv) 131 } 132 133 func getQueryServiceGRPCClient() pb.QueryServiceClient { 134 conn, err := grpc.Dial(queryServiceAddress, testing.NewGRPCDialOptions(logger)...) 135 if err != nil { 136 logger.Fatalf("Failed to connect to Open Match, got %v", err) 137 } 138 return pb.NewQueryServiceClient(conn) 139 } 140 141 func queryPoolsWrapper(mmf func(req *pb.MatchProfile, poolBackfills map[string][]*pb.Backfill, poolTickets map[string][]*pb.Ticket) ([]*pb.Match, error)) matchFunction { 142 var q pb.QueryServiceClient 143 var startQ sync.Once 144 145 return func(req *pb.RunRequest, stream pb.MatchFunction_RunServer) error { 146 startQ.Do(func() { 147 q = getQueryServiceGRPCClient() 148 }) 149 150 poolTickets, err := matchfunction.QueryPools(stream.Context(), q, req.GetProfile().GetPools()) 151 if err != nil { 152 return err 153 } 154 155 poolBackfills, err := matchfunction.QueryBackfillPools(stream.Context(), q, req.GetProfile().GetPools()) 156 if err != nil { 157 return err 158 } 159 160 proposals, err := mmf(req.GetProfile(), poolBackfills, poolTickets) 161 if err != nil { 162 return err 163 } 164 165 logger.WithFields(logrus.Fields{ 166 "proposals": proposals, 167 }).Trace("proposals returned by match function") 168 169 for _, proposal := range proposals { 170 if err := stream.Send(&pb.RunResponse{Proposal: proposal}); err != nil { 171 return err 172 } 173 } 174 175 return nil 176 } 177 }