Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(20)

Side by Side Diff: base/metrics/field_trial.cc

Issue 2365273004: Initial implementation for sharing field trial state (win) (Closed)
Patch Set: add missing include Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "base/metrics/field_trial.h" 5 #include "base/metrics/field_trial.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <utility> 8 #include <utility>
9 9
10 #include "base/base_switches.h"
10 #include "base/build_time.h" 11 #include "base/build_time.h"
12 #include "base/command_line.h"
13 #include "base/feature_list.h"
11 #include "base/logging.h" 14 #include "base/logging.h"
12 #include "base/rand_util.h" 15 #include "base/rand_util.h"
13 #include "base/strings/string_number_conversions.h" 16 #include "base/strings/string_number_conversions.h"
14 #include "base/strings/string_util.h" 17 #include "base/strings/string_util.h"
15 #include "base/strings/stringprintf.h" 18 #include "base/strings/stringprintf.h"
16 #include "base/strings/utf_string_conversions.h" 19 #include "base/strings/utf_string_conversions.h"
17 20
18 namespace base { 21 namespace base {
19 22
20 namespace { 23 namespace {
21 24
22 // Define a separator character to use when creating a persistent form of an 25 // Define a separator character to use when creating a persistent form of an
23 // instance. This is intended for use as a command line argument, passed to a 26 // instance. This is intended for use as a command line argument, passed to a
24 // second process to mimic our state (i.e., provide the same group name). 27 // second process to mimic our state (i.e., provide the same group name).
25 const char kPersistentStringSeparator = '/'; // Currently a slash. 28 const char kPersistentStringSeparator = '/'; // Currently a slash.
26 29
27 // Define a marker character to be used as a prefix to a trial name on the 30 // Define a marker character to be used as a prefix to a trial name on the
28 // command line which forces its activation. 31 // command line which forces its activation.
29 const char kActivationMarker = '*'; 32 const char kActivationMarker = '*';
30 33
34 // Use shared memory to communicate field trial (experiment) state.
35 const base::Feature kShareFieldTrialStateViaSharedMemory{
36 "ShareFieldTrialStateViaSharedMemory", base::FEATURE_DISABLED_BY_DEFAULT};
Alexei Svitkine (slow) 2016/10/06 21:39:28 Nit: How about "UseSharedMemoryForFieldTrials" - a
lawrencewu 2016/10/07 15:07:21 Done.
37
31 // Created a time value based on |year|, |month| and |day_of_month| parameters. 38 // Created a time value based on |year|, |month| and |day_of_month| parameters.
32 Time CreateTimeFromParams(int year, int month, int day_of_month) { 39 Time CreateTimeFromParams(int year, int month, int day_of_month) {
33 DCHECK_GT(year, 1970); 40 DCHECK_GT(year, 1970);
34 DCHECK_GT(month, 0); 41 DCHECK_GT(month, 0);
35 DCHECK_LT(month, 13); 42 DCHECK_LT(month, 13);
36 DCHECK_GT(day_of_month, 0); 43 DCHECK_GT(day_of_month, 0);
37 DCHECK_LT(day_of_month, 32); 44 DCHECK_LT(day_of_month, 32);
38 45
39 Time::Exploded exploded; 46 Time::Exploded exploded;
40 exploded.year = year; 47 exploded.year = year;
(...skipping 510 matching lines...) Expand 10 before | Expand all | Expand 10 after
551 // Call |group()| to mark the trial as "used" and notify observers, if 558 // Call |group()| to mark the trial as "used" and notify observers, if
552 // any. This is useful to ensure that field trials created in child 559 // any. This is useful to ensure that field trials created in child
553 // processes are properly reported in crash reports. 560 // processes are properly reported in crash reports.
554 trial->group(); 561 trial->group();
555 } 562 }
556 } 563 }
557 return true; 564 return true;
558 } 565 }
559 566
560 // static 567 // static
568 void FieldTrialList::CreateTrialsFromCommandLine(
569 const base::CommandLine& cmd_line,
570 const char* field_trial_handle_switch) {
571 DCHECK(global_);
572
573 #if defined(OS_WIN)
574 if (cmd_line.HasSwitch(field_trial_handle_switch)) {
575 std::string arg = cmd_line.GetSwitchValueASCII(field_trial_handle_switch);
576 size_t token = arg.find(",");
577 int field_trial_handle = std::stoi(arg.substr(0, token));
578 int field_trial_length = std::stoi(arg.substr(token + 1, arg.length()));
Alexei Svitkine (slow) 2016/10/06 21:39:28 Do you need to do any kind of error handling here?
lawrencewu 2016/10/07 15:07:21 I thought about it, and I think it is unnecessary
579
580 HANDLE handle = reinterpret_cast<HANDLE>(field_trial_handle);
581 base::SharedMemoryHandle shm_handle =
582 base::SharedMemoryHandle(handle, base::GetCurrentProcId());
583
584 base::SharedMemory shared_memory(shm_handle, false);
Alexei Svitkine (slow) 2016/10/06 21:39:28 Add a comment that this will be deleted when this
lawrencewu 2016/10/07 15:07:21 Done.
585 shared_memory.Map(field_trial_length);
586
587 char* field_trial_state = static_cast<char*>(shared_memory.memory());
588 bool result = FieldTrialList::CreateTrialsFromString(
589 std::string(field_trial_state), std::set<std::string>());
590 DCHECK(result);
591 return;
592 }
593 #endif
594
595 if (cmd_line.HasSwitch(switches::kForceFieldTrials)) {
596 bool result = FieldTrialList::CreateTrialsFromString(
597 cmd_line.GetSwitchValueASCII(switches::kForceFieldTrials),
598 std::set<std::string>());
599 DCHECK(result);
600 }
601 }
602
603 // static
604 std::unique_ptr<base::SharedMemory> FieldTrialList::CopyFieldTrialStateToFlags(
605 const char* field_trial_handle_switch,
606 base::CommandLine* cmd_line) {
607 std::string field_trial_states;
608 base::FieldTrialList::AllStatesToString(&field_trial_states);
609 if (!field_trial_states.empty()) {
610 // Use shared memory to pass the state if the feature is enabled, otherwise
611 // fallback to passing it via the command line as a string.
612 if (base::FeatureList::IsEnabled(kShareFieldTrialStateViaSharedMemory)) {
613 #if defined(OS_WIN)
Alexei Svitkine (slow) 2016/10/06 21:39:28 Put the whole if under ifdef and remove the else -
lawrencewu 2016/10/07 15:07:21 Done.
614 std::unique_ptr<base::SharedMemory> shm(new base::SharedMemory());
615 size_t length = field_trial_states.size() + 1;
616 shm->CreateAndMapAnonymous(length);
617 memcpy(shm->memory(), field_trial_states.c_str(), length);
Alexei Svitkine (slow) 2016/10/06 21:39:28 Is it guaranteed to be null terminated? If not, pl
lawrencewu 2016/10/07 15:07:21 c_str() is guaranteed to be null terminated: http:
618
619 // HANDLE is just typedef'd to void *
620 auto uintptr_handle =
621 reinterpret_cast<std::uintptr_t>(shm->handle().GetHandle());
622 std::string field_trial_handle =
623 std::to_string(uintptr_handle) + "," + std::to_string(length);
624
625 cmd_line->AppendSwitchASCII(field_trial_handle_switch,
626 field_trial_handle);
627 return shm;
628 #else
629 return std::unique_ptr<base::SharedMemory>(nullptr);
630 #endif
631 } else {
632 cmd_line->AppendSwitchASCII(switches::kForceFieldTrials,
633 field_trial_states);
634 }
635 }
636 return std::unique_ptr<base::SharedMemory>(nullptr);
637 }
638
639 // static
561 FieldTrial* FieldTrialList::CreateFieldTrial( 640 FieldTrial* FieldTrialList::CreateFieldTrial(
562 const std::string& name, 641 const std::string& name,
563 const std::string& group_name) { 642 const std::string& group_name) {
564 DCHECK(global_); 643 DCHECK(global_);
565 DCHECK_GE(name.size(), 0u); 644 DCHECK_GE(name.size(), 0u);
566 DCHECK_GE(group_name.size(), 0u); 645 DCHECK_GE(group_name.size(), 0u);
567 if (name.empty() || group_name.empty() || !global_) 646 if (name.empty() || group_name.empty() || !global_)
568 return NULL; 647 return NULL;
569 648
570 FieldTrial* field_trial = FieldTrialList::Find(name); 649 FieldTrial* field_trial = FieldTrialList::Find(name);
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
650 return; 729 return;
651 } 730 }
652 AutoLock auto_lock(global_->lock_); 731 AutoLock auto_lock(global_->lock_);
653 CHECK(!global_->PreLockedFind(trial->trial_name())) << trial->trial_name(); 732 CHECK(!global_->PreLockedFind(trial->trial_name())) << trial->trial_name();
654 trial->AddRef(); 733 trial->AddRef();
655 trial->SetTrialRegistered(); 734 trial->SetTrialRegistered();
656 global_->registered_[trial->trial_name()] = trial; 735 global_->registered_[trial->trial_name()] = trial;
657 } 736 }
658 737
659 } // namespace base 738 } // namespace base
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698