diff --git a/Makefile b/Makefile
index 6d15a57745db9b79f70ee0363ccc460bc7da84d2..e4dc2a61272eee1ff144018c6d1d20017314bb10 100644
--- a/Makefile
+++ b/Makefile
@@ -104,17 +104,40 @@ CXX_basicprof = $(DEFAULT_CXX)
 LD_basicprof = $(DEFAULT_CC)
 LDXX_basicprof = $(DEFAULT_CXX)
 CPPFLAGS_basicprof = -O2 -DGRPC_BASIC_PROFILER -DGRPC_TIMERS_RDTSC
-LDFLAGS_basicprof =
 DEFINES_basicprof = NDEBUG
 
-VALID_CONFIG_stapprof = 1
-CC_stapprof = $(DEFAULT_CC)
-CXX_stapprof = $(DEFAULT_CXX)
-LD_stapprof = $(DEFAULT_CC)
-LDXX_stapprof = $(DEFAULT_CXX)
-CPPFLAGS_stapprof = -O2 -DGRPC_STAP_PROFILER
-LDFLAGS_stapprof =
-DEFINES_stapprof = NDEBUG
+VALID_CONFIG_helgrind = 1
+CC_helgrind = $(DEFAULT_CC)
+CXX_helgrind = $(DEFAULT_CXX)
+LD_helgrind = $(DEFAULT_CC)
+LDXX_helgrind = $(DEFAULT_CXX)
+CPPFLAGS_helgrind = -O0
+LDFLAGS_helgrind = -rdynamic
+DEFINES_helgrind = _DEBUG DEBUG
+DEFINES_helgrind += GRPC_TEST_SLOWDOWN_BUILD_FACTOR=20
+
+VALID_CONFIG_asan-noleaks = 1
+REQUIRE_CUSTOM_LIBRARIES_asan-noleaks = 1
+CC_asan-noleaks = clang
+CXX_asan-noleaks = clang++
+LD_asan-noleaks = clang
+LDXX_asan-noleaks = clang++
+CFLAGS_asan-noleaks = -O0 -fsanitize=address -fno-omit-frame-pointer -Wno-unused-command-line-argument
+CXXFLAGS_asan-noleaks = -O0 -fsanitize=address -fno-omit-frame-pointer -Wno-unused-command-line-argument
+LDFLAGS_asan-noleaks = -fsanitize=address
+DEFINES_asan-noleaks += GRPC_TEST_SLOWDOWN_BUILD_FACTOR=1.5
+
+VALID_CONFIG_ubsan = 1
+REQUIRE_CUSTOM_LIBRARIES_ubsan = 1
+CC_ubsan = clang
+CXX_ubsan = clang++
+LD_ubsan = clang
+LDXX_ubsan = clang++
+CFLAGS_ubsan = -O1 -fsanitize=undefined -fno-omit-frame-pointer -Wno-unused-command-line-argument
+CXXFLAGS_ubsan = -O1 -fsanitize=undefined -fno-omit-frame-pointer -Wno-unused-command-line-argument
+LDFLAGS_ubsan = -fsanitize=undefined
+DEFINES_ubsan = NDEBUG
+DEFINES_ubsan += GRPC_TEST_SLOWDOWN_BUILD_FACTOR=1.5
 
 VALID_CONFIG_dbg = 1
 CC_dbg = $(DEFAULT_CC)
@@ -125,35 +148,33 @@ CPPFLAGS_dbg = -O0
 LDFLAGS_dbg = -rdynamic
 DEFINES_dbg = _DEBUG DEBUG
 
-VALID_CONFIG_mutrace = 1
-CC_mutrace = $(DEFAULT_CC)
-CXX_mutrace = $(DEFAULT_CXX)
-LD_mutrace = $(DEFAULT_CC)
-LDXX_mutrace = $(DEFAULT_CXX)
-CPPFLAGS_mutrace = -O0
-LDFLAGS_mutrace = -rdynamic
-DEFINES_mutrace = _DEBUG DEBUG
+VALID_CONFIG_stapprof = 1
+CC_stapprof = $(DEFAULT_CC)
+CXX_stapprof = $(DEFAULT_CXX)
+LD_stapprof = $(DEFAULT_CC)
+LDXX_stapprof = $(DEFAULT_CXX)
+CPPFLAGS_stapprof = -O2 -DGRPC_STAP_PROFILER
+DEFINES_stapprof = NDEBUG
 
-VALID_CONFIG_valgrind = 1
-REQUIRE_CUSTOM_LIBRARIES_valgrind = 1
-CC_valgrind = $(DEFAULT_CC)
-CXX_valgrind = $(DEFAULT_CXX)
-LD_valgrind = $(DEFAULT_CC)
-LDXX_valgrind = $(DEFAULT_CXX)
-CPPFLAGS_valgrind = -O0
-LDFLAGS_valgrind = -rdynamic
-DEFINES_valgrind = _DEBUG DEBUG GRPC_TEST_SLOWDOWN_BUILD_FACTOR=20
+VALID_CONFIG_gcov = 1
+CC_gcov = gcc
+CXX_gcov = g++
+LD_gcov = gcc
+LDXX_gcov = g++
+CFLAGS_gcov = -O0 -fprofile-arcs -ftest-coverage -Wno-return-type
+CXXFLAGS_gcov = -O0 -fprofile-arcs -ftest-coverage -Wno-return-type
+LDFLAGS_gcov = -fprofile-arcs -ftest-coverage -rdynamic
+DEFINES_gcov = _DEBUG DEBUG GPR_GCOV
 
-VALID_CONFIG_tsan = 1
-REQUIRE_CUSTOM_LIBRARIES_tsan = 1
-CC_tsan = clang
-CXX_tsan = clang++
-LD_tsan = clang
-LDXX_tsan = clang++
-CFLAGS_tsan = -O0 -fsanitize=thread -fno-omit-frame-pointer -Wno-unused-command-line-argument -fPIE -pie
-CXXFLAGS_tsan = -O0 -fsanitize=thread -fno-omit-frame-pointer -Wno-unused-command-line-argument -fPIE -pie
-LDFLAGS_tsan = -fsanitize=thread -fPIE -pie $(if $(JENKINS_BUILD),-Wl$(comma)-Ttext-segment=0x7e0000000000,)
-DEFINES_tsan = NDEBUG GRPC_TEST_SLOWDOWN_BUILD_FACTOR=10
+VALID_CONFIG_memcheck = 1
+CC_memcheck = $(DEFAULT_CC)
+CXX_memcheck = $(DEFAULT_CXX)
+LD_memcheck = $(DEFAULT_CC)
+LDXX_memcheck = $(DEFAULT_CXX)
+CPPFLAGS_memcheck = -O0
+LDFLAGS_memcheck = -rdynamic
+DEFINES_memcheck = _DEBUG DEBUG
+DEFINES_memcheck += GRPC_TEST_SLOWDOWN_BUILD_FACTOR=10
 
 VALID_CONFIG_asan = 1
 REQUIRE_CUSTOM_LIBRARIES_asan = 1
@@ -164,39 +185,40 @@ LDXX_asan = clang++
 CFLAGS_asan = -O0 -fsanitize=address -fno-omit-frame-pointer -Wno-unused-command-line-argument
 CXXFLAGS_asan = -O0 -fsanitize=address -fno-omit-frame-pointer -Wno-unused-command-line-argument
 LDFLAGS_asan = -fsanitize=address
-DEFINES_asan = GRPC_TEST_SLOWDOWN_BUILD_FACTOR=3
+DEFINES_asan += GRPC_TEST_SLOWDOWN_BUILD_FACTOR=1.5
+
+VALID_CONFIG_tsan = 1
+REQUIRE_CUSTOM_LIBRARIES_tsan = 1
+CC_tsan = clang
+CXX_tsan = clang++
+LD_tsan = clang
+LDXX_tsan = clang++
+CFLAGS_tsan = -O0 -fsanitize=thread -fno-omit-frame-pointer -Wno-unused-command-line-argument -fPIE -pie
+CXXFLAGS_tsan = -O0 -fsanitize=thread -fno-omit-frame-pointer -Wno-unused-command-line-argument -fPIE -pie
+LDFLAGS_tsan = -fsanitize=thread -fPIE -pie $(if $(JENKINS_BUILD),-Wl$(comma)-Ttext-segment=0x7e0000000000,)
+DEFINES_tsan += GRPC_TEST_SLOWDOWN_BUILD_FACTOR=2
 
 VALID_CONFIG_msan = 1
 REQUIRE_CUSTOM_LIBRARIES_msan = 1
 CC_msan = clang
-CXX_msan = clang++-libc++
+CXX_msan = clang++
 LD_msan = clang
-LDXX_msan = clang++-libc++
+LDXX_msan = clang++
 CFLAGS_msan = -O0 -fsanitize=memory -fsanitize-memory-track-origins -fno-omit-frame-pointer -DGTEST_HAS_TR1_TUPLE=0 -DGTEST_USE_OWN_TR1_TUPLE=1 -Wno-unused-command-line-argument -fPIE -pie
 CXXFLAGS_msan = -O0 -fsanitize=memory -fsanitize-memory-track-origins -fno-omit-frame-pointer -DGTEST_HAS_TR1_TUPLE=0 -DGTEST_USE_OWN_TR1_TUPLE=1 -Wno-unused-command-line-argument -fPIE -pie
 LDFLAGS_msan = -fsanitize=memory -DGTEST_HAS_TR1_TUPLE=0 -DGTEST_USE_OWN_TR1_TUPLE=1 -fPIE -pie $(if $(JENKINS_BUILD),-Wl$(comma)-Ttext-segment=0x7e0000000000,)
-DEFINES_msan = NDEBUG GRPC_TEST_SLOWDOWN_BUILD_FACTOR=4
+DEFINES_msan = NDEBUG
+DEFINES_msan += GRPC_TEST_SLOWDOWN_BUILD_FACTOR=1.5
 
-VALID_CONFIG_ubsan = 1
-REQUIRE_CUSTOM_LIBRARIES_ubsan = 1
-CC_ubsan = clang
-CXX_ubsan = clang++
-LD_ubsan = clang
-LDXX_ubsan = clang++
-CFLAGS_ubsan = -O1 -fsanitize=undefined -fno-omit-frame-pointer -Wno-unused-command-line-argument
-CXXFLAGS_ubsan = -O1 -fsanitize=undefined -fno-omit-frame-pointer -Wno-unused-command-line-argument
-LDFLAGS_ubsan = -fsanitize=undefined
-DEFINES_ubsan = NDEBUG GRPC_TEST_SLOWDOWN_BUILD_FACTOR=3
+VALID_CONFIG_mutrace = 1
+CC_mutrace = $(DEFAULT_CC)
+CXX_mutrace = $(DEFAULT_CXX)
+LD_mutrace = $(DEFAULT_CC)
+LDXX_mutrace = $(DEFAULT_CXX)
+CPPFLAGS_mutrace = -O0
+LDFLAGS_mutrace = -rdynamic
+DEFINES_mutrace = _DEBUG DEBUG
 
-VALID_CONFIG_gcov = 1
-CC_gcov = gcc
-CXX_gcov = g++
-LD_gcov = gcc
-LDXX_gcov = g++
-CFLAGS_gcov = -O0 -fprofile-arcs -ftest-coverage -Wno-return-type
-CXXFLAGS_gcov = -O0 -fprofile-arcs -ftest-coverage -Wno-return-type
-LDFLAGS_gcov = -fprofile-arcs -ftest-coverage -rdynamic
-DEFINES_gcov = _DEBUG DEBUG GPR_GCOV
 
 
 # General settings.
diff --git a/build.yaml b/build.yaml
index 61a28cb25607ece909fa576b528a89acffe86d88..cf53af57d82fff8cd48c9661a0d9bf62206db045 100644
--- a/build.yaml
+++ b/build.yaml
@@ -2481,6 +2481,112 @@ vspackages:
   props: false
   redist: false
   version: 1.7.0.1
+configs:
+  asan:
+    CC: clang
+    CFLAGS: -O0 -fsanitize=address -fno-omit-frame-pointer -Wno-unused-command-line-argument
+    CXX: clang++
+    CXXFLAGS: -O0 -fsanitize=address -fno-omit-frame-pointer -Wno-unused-command-line-argument
+    LD: clang
+    LDFLAGS: -fsanitize=address
+    LDXX: clang++
+    compile_the_world: true
+    test_environ:
+      ASAN_OPTIONS: suppressions=tools/asan_suppressions.txt:detect_leaks=1:color=always
+      LSAN_OPTIONS: suppressions=tools/asan_suppressions.txt:report_objects=1
+    timeout_multiplier: 1.5
+  asan-noleaks:
+    CC: clang
+    CFLAGS: -O0 -fsanitize=address -fno-omit-frame-pointer -Wno-unused-command-line-argument
+    CXX: clang++
+    CXXFLAGS: -O0 -fsanitize=address -fno-omit-frame-pointer -Wno-unused-command-line-argument
+    LD: clang
+    LDFLAGS: -fsanitize=address
+    LDXX: clang++
+    compile_the_world: true
+    test_environ:
+      ASAN_OPTIONS: detect_leaks=0:color=always
+    timeout_multiplier: 1.5
+  basicprof:
+    CPPFLAGS: -O2 -DGRPC_BASIC_PROFILER -DGRPC_TIMERS_RDTSC
+    DEFINES: NDEBUG
+  dbg:
+    CPPFLAGS: -O0
+    DEFINES: _DEBUG DEBUG
+    LDFLAGS: -rdynamic
+  gcov:
+    CC: gcc
+    CFLAGS: -O0 -fprofile-arcs -ftest-coverage -Wno-return-type
+    CXX: g++
+    CXXFLAGS: -O0 -fprofile-arcs -ftest-coverage -Wno-return-type
+    DEFINES: _DEBUG DEBUG GPR_GCOV
+    LD: gcc
+    LDFLAGS: -fprofile-arcs -ftest-coverage -rdynamic
+    LDXX: g++
+  helgrind:
+    CPPFLAGS: -O0
+    DEFINES: _DEBUG DEBUG
+    LDFLAGS: -rdynamic
+    timeout_multiplier: 20
+    valgrind: --tool=helgrind
+  memcheck:
+    CPPFLAGS: -O0
+    DEFINES: _DEBUG DEBUG
+    LDFLAGS: -rdynamic
+    timeout_multiplier: 10
+    valgrind: --tool=memcheck --leak-check=full
+  msan:
+    CC: clang
+    CFLAGS: -O0 -fsanitize=memory -fsanitize-memory-track-origins -fno-omit-frame-pointer
+      -DGTEST_HAS_TR1_TUPLE=0 -DGTEST_USE_OWN_TR1_TUPLE=1 -Wno-unused-command-line-argument
+      -fPIE -pie
+    CXX: clang++
+    CXXFLAGS: -O0 -fsanitize=memory -fsanitize-memory-track-origins -fno-omit-frame-pointer
+      -DGTEST_HAS_TR1_TUPLE=0 -DGTEST_USE_OWN_TR1_TUPLE=1 -Wno-unused-command-line-argument
+      -fPIE -pie
+    DEFINES: NDEBUG
+    LD: clang
+    LDFLAGS: -fsanitize=memory -DGTEST_HAS_TR1_TUPLE=0 -DGTEST_USE_OWN_TR1_TUPLE=1
+      -fPIE -pie $(if $(JENKINS_BUILD),-Wl$(comma)-Ttext-segment=0x7e0000000000,)
+    LDXX: clang++
+    compile_the_world: true
+    timeout_multiplier: 1.5
+  mutrace:
+    CPPFLAGS: -O0
+    DEFINES: _DEBUG DEBUG
+    LDFLAGS: -rdynamic
+  opt:
+    CPPFLAGS: -O2
+    DEFINES: NDEBUG
+    LDFLAGS: -rdynamic
+  stapprof:
+    CPPFLAGS: -O2 -DGRPC_STAP_PROFILER
+    DEFINES: NDEBUG
+  tsan:
+    CC: clang
+    CFLAGS: -O0 -fsanitize=thread -fno-omit-frame-pointer -Wno-unused-command-line-argument
+      -fPIE -pie
+    CXX: clang++
+    CXXFLAGS: -O0 -fsanitize=thread -fno-omit-frame-pointer -Wno-unused-command-line-argument
+      -fPIE -pie
+    LD: clang
+    LDFLAGS: -fsanitize=thread -fPIE -pie $(if $(JENKINS_BUILD),-Wl$(comma)-Ttext-segment=0x7e0000000000,)
+    LDXX: clang++
+    compile_the_world: true
+    test_environ:
+      TSAN_OPTIONS: suppressions=tools/tsan_suppressions.txt:halt_on_error=1:second_deadlock_stack=1
+    timeout_multiplier: 2
+  ubsan:
+    CC: clang
+    CFLAGS: -O1 -fsanitize=undefined -fno-omit-frame-pointer -Wno-unused-command-line-argument
+    CXX: clang++
+    CXXFLAGS: -O1 -fsanitize=undefined -fno-omit-frame-pointer -Wno-unused-command-line-argument
+    DEFINES: NDEBUG
+    LD: clang
+    LDFLAGS: -fsanitize=undefined
+    LDXX: clang++
+    compile_the_world: true
+    timeout_multiplier: 1.5
 node_modules:
 - deps:
   - grpc
diff --git a/templates/Makefile.template b/templates/Makefile.template
index 4353a0de3a8972867d81b7521f19501e36aeee15..9d8a824167282b3a960e8c8899c173c90566fb33 100644
--- a/templates/Makefile.template
+++ b/templates/Makefile.template
@@ -105,114 +105,24 @@
 
   # Configurations
 
-  VALID_CONFIG_opt = 1
-  CC_opt = $(DEFAULT_CC)
-  CXX_opt = $(DEFAULT_CXX)
-  LD_opt = $(DEFAULT_CC)
-  LDXX_opt = $(DEFAULT_CXX)
-  CPPFLAGS_opt = -O2
-  LDFLAGS_opt = -rdynamic
-  DEFINES_opt = NDEBUG
-
-  VALID_CONFIG_basicprof = 1
-  CC_basicprof = $(DEFAULT_CC)
-  CXX_basicprof = $(DEFAULT_CXX)
-  LD_basicprof = $(DEFAULT_CC)
-  LDXX_basicprof = $(DEFAULT_CXX)
-  CPPFLAGS_basicprof = -O2 -DGRPC_BASIC_PROFILER -DGRPC_TIMERS_RDTSC
-  LDFLAGS_basicprof =
-  DEFINES_basicprof = NDEBUG
-
-  VALID_CONFIG_stapprof = 1
-  CC_stapprof = $(DEFAULT_CC)
-  CXX_stapprof = $(DEFAULT_CXX)
-  LD_stapprof = $(DEFAULT_CC)
-  LDXX_stapprof = $(DEFAULT_CXX)
-  CPPFLAGS_stapprof = -O2 -DGRPC_STAP_PROFILER
-  LDFLAGS_stapprof =
-  DEFINES_stapprof = NDEBUG
-
-  VALID_CONFIG_dbg = 1
-  CC_dbg = $(DEFAULT_CC)
-  CXX_dbg = $(DEFAULT_CXX)
-  LD_dbg = $(DEFAULT_CC)
-  LDXX_dbg = $(DEFAULT_CXX)
-  CPPFLAGS_dbg = -O0
-  LDFLAGS_dbg = -rdynamic
-  DEFINES_dbg = _DEBUG DEBUG
-
-  VALID_CONFIG_mutrace = 1
-  CC_mutrace = $(DEFAULT_CC)
-  CXX_mutrace = $(DEFAULT_CXX)
-  LD_mutrace = $(DEFAULT_CC)
-  LDXX_mutrace = $(DEFAULT_CXX)
-  CPPFLAGS_mutrace = -O0
-  LDFLAGS_mutrace = -rdynamic
-  DEFINES_mutrace = _DEBUG DEBUG
-
-  VALID_CONFIG_valgrind = 1
-  REQUIRE_CUSTOM_LIBRARIES_valgrind = 1
-  CC_valgrind = $(DEFAULT_CC)
-  CXX_valgrind = $(DEFAULT_CXX)
-  LD_valgrind = $(DEFAULT_CC)
-  LDXX_valgrind = $(DEFAULT_CXX)
-  CPPFLAGS_valgrind = -O0
-  LDFLAGS_valgrind = -rdynamic
-  DEFINES_valgrind = _DEBUG DEBUG GRPC_TEST_SLOWDOWN_BUILD_FACTOR=20
-
-  VALID_CONFIG_tsan = 1
-  REQUIRE_CUSTOM_LIBRARIES_tsan = 1
-  CC_tsan = clang
-  CXX_tsan = clang++
-  LD_tsan = clang
-  LDXX_tsan = clang++
-  CFLAGS_tsan = -O0 -fsanitize=thread -fno-omit-frame-pointer -Wno-unused-command-line-argument -fPIE -pie
-  CXXFLAGS_tsan = -O0 -fsanitize=thread -fno-omit-frame-pointer -Wno-unused-command-line-argument -fPIE -pie
-  LDFLAGS_tsan = -fsanitize=thread -fPIE -pie $(if $(JENKINS_BUILD),-Wl$(comma)-Ttext-segment=0x7e0000000000,)
-  DEFINES_tsan = NDEBUG GRPC_TEST_SLOWDOWN_BUILD_FACTOR=10
-
-  VALID_CONFIG_asan = 1
-  REQUIRE_CUSTOM_LIBRARIES_asan = 1
-  CC_asan = clang
-  CXX_asan = clang++
-  LD_asan = clang
-  LDXX_asan = clang++
-  CFLAGS_asan = -O0 -fsanitize=address -fno-omit-frame-pointer -Wno-unused-command-line-argument
-  CXXFLAGS_asan = -O0 -fsanitize=address -fno-omit-frame-pointer -Wno-unused-command-line-argument
-  LDFLAGS_asan = -fsanitize=address
-  DEFINES_asan = GRPC_TEST_SLOWDOWN_BUILD_FACTOR=3
-
-  VALID_CONFIG_msan = 1
-  REQUIRE_CUSTOM_LIBRARIES_msan = 1
-  CC_msan = clang
-  CXX_msan = clang++-libc++
-  LD_msan = clang
-  LDXX_msan = clang++-libc++
-  CFLAGS_msan = -O0 -fsanitize=memory -fsanitize-memory-track-origins -fno-omit-frame-pointer -DGTEST_HAS_TR1_TUPLE=0 -DGTEST_USE_OWN_TR1_TUPLE=1 -Wno-unused-command-line-argument -fPIE -pie
-  CXXFLAGS_msan = -O0 -fsanitize=memory -fsanitize-memory-track-origins -fno-omit-frame-pointer -DGTEST_HAS_TR1_TUPLE=0 -DGTEST_USE_OWN_TR1_TUPLE=1 -Wno-unused-command-line-argument -fPIE -pie
-  LDFLAGS_msan = -fsanitize=memory -DGTEST_HAS_TR1_TUPLE=0 -DGTEST_USE_OWN_TR1_TUPLE=1 -fPIE -pie $(if $(JENKINS_BUILD),-Wl$(comma)-Ttext-segment=0x7e0000000000,)
-  DEFINES_msan = NDEBUG GRPC_TEST_SLOWDOWN_BUILD_FACTOR=4
-
-  VALID_CONFIG_ubsan = 1
-  REQUIRE_CUSTOM_LIBRARIES_ubsan = 1
-  CC_ubsan = clang
-  CXX_ubsan = clang++
-  LD_ubsan = clang
-  LDXX_ubsan = clang++
-  CFLAGS_ubsan = -O1 -fsanitize=undefined -fno-omit-frame-pointer -Wno-unused-command-line-argument
-  CXXFLAGS_ubsan = -O1 -fsanitize=undefined -fno-omit-frame-pointer -Wno-unused-command-line-argument
-  LDFLAGS_ubsan = -fsanitize=undefined
-  DEFINES_ubsan = NDEBUG GRPC_TEST_SLOWDOWN_BUILD_FACTOR=3
-
-  VALID_CONFIG_gcov = 1
-  CC_gcov = gcc
-  CXX_gcov = g++
-  LD_gcov = gcc
-  LDXX_gcov = g++
-  CFLAGS_gcov = -O0 -fprofile-arcs -ftest-coverage -Wno-return-type
-  CXXFLAGS_gcov = -O0 -fprofile-arcs -ftest-coverage -Wno-return-type
-  LDFLAGS_gcov = -fprofile-arcs -ftest-coverage -rdynamic
-  DEFINES_gcov = _DEBUG DEBUG GPR_GCOV
+  % for name, args in configs.iteritems():
+  VALID_CONFIG_${name} = 1
+  %  if args.get('compile_the_world', False):
+  REQUIRE_CUSTOM_LIBRARIES_${name} = 1
+  %  endif
+  %  for tool, default in [('CC', 'CC'), ('CXX', 'CXX'), ('LD', 'CC'), ('LDXX', 'CXX')]:
+  ${tool}_${name} = ${args.get(tool, '$(DEFAULT_%s)' % default)}
+  %  endfor
+  %  for arg in ['CFLAGS', 'CXXFLAGS', 'CPPFLAGS', 'LDFLAGS', 'DEFINES']:
+  %   if args.get(arg, None) is not None:
+  ${arg}_${name} = ${args.get(arg)}
+  %   endif
+  %  endfor
+  %  if args.get('timeout_multiplier', 1) != 1:
+  DEFINES_${name} += GRPC_TEST_SLOWDOWN_BUILD_FACTOR=${args.timeout_multiplier}
+  %  endif
+
+  % endfor
 
 
   # General settings.
diff --git a/templates/tools/run_tests/configs.json.template b/templates/tools/run_tests/configs.json.template
new file mode 100644
index 0000000000000000000000000000000000000000..5c82dfb34794c3bd4697f67a12b8d68b69be524d
--- /dev/null
+++ b/templates/tools/run_tests/configs.json.template
@@ -0,0 +1,17 @@
+%YAML 1.2
+--- |
+  <%
+  import json
+  out_configs = []
+  for name, args in configs.iteritems():
+    config_args={}
+    config_args['config'] = name
+    if args.get('valgrind', None) is not None:
+      config_args['tool_prefix'] = ['valgrind'] + args.valgrind.split(' ')
+    if args.get('timeout_multiplier', 1) != 1:
+      config_args['timeout_multiplier'] = args.timeout_multiplier
+    if args.get('test_environ', None) is not None:
+      config_args['environ'] = args.test_environ
+    out_configs.append(config_args)
+  %>\
+  ${json.dumps(out_configs, sort_keys=True, indent=2)}
diff --git a/tools/run_tests/configs.json b/tools/run_tests/configs.json
new file mode 100644
index 0000000000000000000000000000000000000000..769942df996165e9661bb95de955d2105140a8c4
--- /dev/null
+++ b/tools/run_tests/configs.json
@@ -0,0 +1,67 @@
+[
+  {
+    "config": "opt"
+  }, 
+  {
+    "config": "basicprof"
+  }, 
+  {
+    "config": "helgrind", 
+    "timeout_multiplier": 20, 
+    "tool_prefix": [
+      "valgrind", 
+      "--tool=helgrind"
+    ]
+  }, 
+  {
+    "config": "asan-noleaks", 
+    "environ": {
+      "ASAN_OPTIONS": "detect_leaks=0:color=always"
+    }, 
+    "timeout_multiplier": 1.5
+  }, 
+  {
+    "config": "ubsan", 
+    "timeout_multiplier": 1.5
+  }, 
+  {
+    "config": "dbg"
+  }, 
+  {
+    "config": "stapprof"
+  }, 
+  {
+    "config": "gcov"
+  }, 
+  {
+    "config": "memcheck", 
+    "timeout_multiplier": 10, 
+    "tool_prefix": [
+      "valgrind", 
+      "--tool=memcheck", 
+      "--leak-check=full"
+    ]
+  }, 
+  {
+    "config": "asan", 
+    "environ": {
+      "ASAN_OPTIONS": "suppressions=tools/asan_suppressions.txt:detect_leaks=1:color=always", 
+      "LSAN_OPTIONS": "suppressions=tools/asan_suppressions.txt:report_objects=1"
+    }, 
+    "timeout_multiplier": 1.5
+  }, 
+  {
+    "config": "tsan", 
+    "environ": {
+      "TSAN_OPTIONS": "suppressions=tools/tsan_suppressions.txt:halt_on_error=1:second_deadlock_stack=1"
+    }, 
+    "timeout_multiplier": 2
+  }, 
+  {
+    "config": "msan", 
+    "timeout_multiplier": 1.5
+  }, 
+  {
+    "config": "mutrace"
+  }
+]
diff --git a/tools/run_tests/run_tests.py b/tools/run_tests/run_tests.py
index 61d8447112a87fea3764a2b3fe6befa075237c3d..f8b01021c88fbfaf0d2c57f680c9edf05f787ccf 100755
--- a/tools/run_tests/run_tests.py
+++ b/tools/run_tests/run_tests.py
@@ -31,6 +31,7 @@
 """Run tests in parallel."""
 
 import argparse
+import ast
 import glob
 import hashlib
 import itertools
@@ -66,15 +67,16 @@ def platform_string():
 
 
 # SimpleConfig: just compile with CONFIG=config, and run the binary to test
-class SimpleConfig(object):
+class Config(object):
 
-  def __init__(self, config, environ=None, timeout_multiplier=1):
+  def __init__(self, config, environ=None, timeout_multiplier=1, tool_prefix=[]):
     if environ is None:
       environ = {}
     self.build_config = config
     self.allow_hashing = (config != 'gcov')
     self.environ = environ
     self.environ['CONFIG'] = config
+    self.tool_prefix = tool_prefix
     self.timeout_multiplier = timeout_multiplier
 
   def job_spec(self, cmdline, hash_targets, timeout_seconds=5*60,
@@ -93,7 +95,7 @@ class SimpleConfig(object):
     actual_environ = self.environ.copy()
     for k, v in environ.iteritems():
       actual_environ[k] = v
-    return jobset.JobSpec(cmdline=cmdline,
+    return jobset.JobSpec(cmdline=self.tool_prefix + cmdline,
                           shortname=shortname,
                           environ=actual_environ,
                           cpu_cost=cpu_cost,
@@ -104,27 +106,6 @@ class SimpleConfig(object):
                           timeout_retries=3 if args.allow_flakes else 0)
 
 
-# ValgrindConfig: compile with some CONFIG=config, but use valgrind to run
-class ValgrindConfig(object):
-
-  def __init__(self, config, tool, args=None):
-    if args is None:
-      args = []
-    self.build_config = config
-    self.tool = tool
-    self.args = args
-    self.allow_hashing = False
-
-  def job_spec(self, cmdline, hash_targets, cpu_cost=1.0):
-    return jobset.JobSpec(cmdline=['valgrind', '--tool=%s' % self.tool] +
-                          self.args + cmdline,
-                          shortname='valgrind %s' % cmdline[0],
-                          hash_targets=None,
-                          cpu_cost=cpu_cost,
-                          flake_retries=5 if args.allow_flakes else 0,
-                          timeout_retries=3 if args.allow_flakes else 0)
-
-
 def get_c_tests(travis, test_lang) :
   out = []
   platforms_str = 'ci_platforms' if travis else 'platforms'
@@ -530,22 +511,8 @@ class Build(object):
 
 
 # different configurations we can run under
-_CONFIGS = {
-    'dbg': SimpleConfig('dbg'),
-    'opt': SimpleConfig('opt'),
-    'tsan': SimpleConfig('tsan', timeout_multiplier=2, environ={
-        'TSAN_OPTIONS': 'suppressions=tools/tsan_suppressions.txt:halt_on_error=1:second_deadlock_stack=1'}),
-    'msan': SimpleConfig('msan', timeout_multiplier=1.5),
-    'ubsan': SimpleConfig('ubsan'),
-    'asan': SimpleConfig('asan', timeout_multiplier=1.5, environ={
-        'ASAN_OPTIONS': 'suppressions=tools/asan_suppressions.txt:detect_leaks=1:color=always',
-        'LSAN_OPTIONS': 'suppressions=tools/asan_suppressions.txt:report_objects=1'}),
-    'asan-noleaks': SimpleConfig('asan', environ={
-        'ASAN_OPTIONS': 'detect_leaks=0:color=always'}),
-    'gcov': SimpleConfig('gcov'),
-    'memcheck': ValgrindConfig('valgrind', 'memcheck', ['--leak-check=full']),
-    'helgrind': ValgrindConfig('dbg', 'helgrind')
-    }
+with open('tools/run_tests/configs.json') as f:
+  _CONFIGS = dict((cfg['config'], Config(**cfg)) for cfg in ast.literal_eval(f.read()))
 
 
 _DEFAULT = ['opt']
@@ -1143,3 +1110,4 @@ else:
   if BuildAndRunError.POST_TEST in errors:
     exit_code |= 4
   sys.exit(exit_code)
+