afdo_test.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463
  1. // Copyright 2022 Google Inc. All rights reserved.
  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. package cc
  15. import (
  16. "strings"
  17. "testing"
  18. "android/soong/android"
  19. "github.com/google/blueprint"
  20. )
  21. type visitDirectDepsInterface interface {
  22. VisitDirectDeps(blueprint.Module, func(dep blueprint.Module))
  23. }
  24. func hasDirectDep(ctx visitDirectDepsInterface, m android.Module, wantDep android.Module) bool {
  25. var found bool
  26. ctx.VisitDirectDeps(m, func(dep blueprint.Module) {
  27. if dep == wantDep {
  28. found = true
  29. }
  30. })
  31. return found
  32. }
  33. func TestAfdoDeps(t *testing.T) {
  34. t.Parallel()
  35. bp := `
  36. cc_library_shared {
  37. name: "libTest",
  38. srcs: ["test.c"],
  39. static_libs: ["libFoo"],
  40. afdo: true,
  41. }
  42. cc_library_static {
  43. name: "libFoo",
  44. srcs: ["foo.c"],
  45. static_libs: ["libBar"],
  46. }
  47. cc_library_static {
  48. name: "libBar",
  49. srcs: ["bar.c"],
  50. }
  51. `
  52. result := android.GroupFixturePreparers(
  53. PrepareForTestWithFdoProfile,
  54. prepareForCcTest,
  55. android.FixtureAddTextFile("afdo_profiles_package/libTest.afdo", ""),
  56. android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
  57. variables.AfdoProfiles = []string{
  58. "libTest://afdo_profiles_package:libTest_afdo",
  59. }
  60. }),
  61. android.MockFS{
  62. "afdo_profiles_package/Android.bp": []byte(`
  63. fdo_profile {
  64. name: "libTest_afdo",
  65. profile: "libTest.afdo",
  66. }
  67. `),
  68. }.AddToFixture(),
  69. ).RunTestWithBp(t, bp)
  70. expectedCFlag := "-fprofile-sample-use=afdo_profiles_package/libTest.afdo"
  71. libTest := result.ModuleForTests("libTest", "android_arm64_armv8-a_shared")
  72. libFooAfdoVariant := result.ModuleForTests("libFoo", "android_arm64_armv8-a_static_afdo-libTest")
  73. libBarAfdoVariant := result.ModuleForTests("libBar", "android_arm64_armv8-a_static_afdo-libTest")
  74. // Check cFlags of afdo-enabled module and the afdo-variant of its static deps
  75. cFlags := libTest.Rule("cc").Args["cFlags"]
  76. if !strings.Contains(cFlags, expectedCFlag) {
  77. t.Errorf("Expected 'libTest' to enable afdo, but did not find %q in cflags %q", expectedCFlag, cFlags)
  78. }
  79. cFlags = libFooAfdoVariant.Rule("cc").Args["cFlags"]
  80. if !strings.Contains(cFlags, expectedCFlag) {
  81. t.Errorf("Expected 'libFooAfdoVariant' to enable afdo, but did not find %q in cflags %q", expectedCFlag, cFlags)
  82. }
  83. cFlags = libBarAfdoVariant.Rule("cc").Args["cFlags"]
  84. if !strings.Contains(cFlags, expectedCFlag) {
  85. t.Errorf("Expected 'libBarAfdoVariant' to enable afdo, but did not find %q in cflags %q", expectedCFlag, cFlags)
  86. }
  87. // Check dependency edge from afdo-enabled module to static deps
  88. if !hasDirectDep(result, libTest.Module(), libFooAfdoVariant.Module()) {
  89. t.Errorf("libTest missing dependency on afdo variant of libFoo")
  90. }
  91. if !hasDirectDep(result, libFooAfdoVariant.Module(), libBarAfdoVariant.Module()) {
  92. t.Errorf("libTest missing dependency on afdo variant of libBar")
  93. }
  94. // Verify non-afdo variant exists and doesn't contain afdo
  95. libFoo := result.ModuleForTests("libFoo", "android_arm64_armv8-a_static")
  96. libBar := result.ModuleForTests("libBar", "android_arm64_armv8-a_static")
  97. cFlags = libFoo.Rule("cc").Args["cFlags"]
  98. if strings.Contains(cFlags, expectedCFlag) {
  99. t.Errorf("Expected 'libFoo' to not enable afdo, but found %q in cflags %q", expectedCFlag, cFlags)
  100. }
  101. cFlags = libBar.Rule("cc").Args["cFlags"]
  102. if strings.Contains(cFlags, expectedCFlag) {
  103. t.Errorf("Expected 'libBar' to not enable afdo, but found %q in cflags %q", expectedCFlag, cFlags)
  104. }
  105. // Check dependency edges of static deps
  106. if hasDirectDep(result, libTest.Module(), libFoo.Module()) {
  107. t.Errorf("libTest should not depend on non-afdo variant of libFoo")
  108. }
  109. if !hasDirectDep(result, libFoo.Module(), libBar.Module()) {
  110. t.Errorf("libFoo missing dependency on non-afdo variant of libBar")
  111. }
  112. }
  113. func TestAfdoEnabledOnStaticDepNoAfdo(t *testing.T) {
  114. t.Parallel()
  115. bp := `
  116. cc_library_shared {
  117. name: "libTest",
  118. srcs: ["foo.c"],
  119. static_libs: ["libFoo"],
  120. }
  121. cc_library_static {
  122. name: "libFoo",
  123. srcs: ["foo.c"],
  124. static_libs: ["libBar"],
  125. afdo: true, // TODO(b/256670524): remove support for enabling afdo from static only libraries, this can only propagate from shared libraries/binaries
  126. }
  127. cc_library_static {
  128. name: "libBar",
  129. }
  130. `
  131. result := android.GroupFixturePreparers(
  132. prepareForCcTest,
  133. PrepareForTestWithFdoProfile,
  134. android.FixtureAddTextFile("toolchain/pgo-profiles/sampling/libFoo.afdo", ""),
  135. android.MockFS{
  136. "afdo_profiles_package/Android.bp": []byte(`
  137. soong_namespace {
  138. }
  139. fdo_profile {
  140. name: "libFoo_afdo",
  141. profile: "libFoo.afdo",
  142. }
  143. `),
  144. }.AddToFixture(),
  145. ).RunTestWithBp(t, bp)
  146. libTest := result.ModuleForTests("libTest", "android_arm64_armv8-a_shared").Module()
  147. libFoo := result.ModuleForTests("libFoo", "android_arm64_armv8-a_static")
  148. libBar := result.ModuleForTests("libBar", "android_arm64_armv8-a_static").Module()
  149. if !hasDirectDep(result, libTest, libFoo.Module()) {
  150. t.Errorf("libTest missing dependency on afdo variant of libFoo")
  151. }
  152. if !hasDirectDep(result, libFoo.Module(), libBar) {
  153. t.Errorf("libFoo missing dependency on afdo variant of libBar")
  154. }
  155. fooVariants := result.ModuleVariantsForTests("foo")
  156. for _, v := range fooVariants {
  157. if strings.Contains(v, "afdo-") {
  158. t.Errorf("Expected no afdo variant of 'foo', got %q", v)
  159. }
  160. }
  161. cFlags := libFoo.Rule("cc").Args["cFlags"]
  162. if w := "-fprofile-sample-accurate"; strings.Contains(cFlags, w) {
  163. t.Errorf("Expected 'foo' to not enable afdo, but found %q in cflags %q", w, cFlags)
  164. }
  165. barVariants := result.ModuleVariantsForTests("bar")
  166. for _, v := range barVariants {
  167. if strings.Contains(v, "afdo-") {
  168. t.Errorf("Expected no afdo variant of 'bar', got %q", v)
  169. }
  170. }
  171. }
  172. func TestAfdoEnabledWithRuntimeDepNoAfdo(t *testing.T) {
  173. bp := `
  174. cc_library {
  175. name: "libTest",
  176. srcs: ["foo.c"],
  177. runtime_libs: ["libFoo"],
  178. afdo: true,
  179. }
  180. cc_library {
  181. name: "libFoo",
  182. }
  183. `
  184. result := android.GroupFixturePreparers(
  185. prepareForCcTest,
  186. PrepareForTestWithFdoProfile,
  187. android.FixtureAddTextFile("afdo_profiles_package/libTest.afdo", ""),
  188. android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
  189. variables.AfdoProfiles = []string{
  190. "libTest://afdo_profiles_package:libTest_afdo",
  191. }
  192. }),
  193. android.MockFS{
  194. "afdo_profiles_package/Android.bp": []byte(`
  195. fdo_profile {
  196. name: "libTest_afdo",
  197. profile: "libTest.afdo",
  198. }
  199. `),
  200. }.AddToFixture(),
  201. ).RunTestWithBp(t, bp)
  202. libFooVariants := result.ModuleVariantsForTests("libFoo")
  203. for _, v := range libFooVariants {
  204. if strings.Contains(v, "afdo-") {
  205. t.Errorf("Expected no afdo variant of 'foo', got %q", v)
  206. }
  207. }
  208. }
  209. func TestAfdoEnabledWithMultiArchs(t *testing.T) {
  210. bp := `
  211. cc_library_shared {
  212. name: "foo",
  213. srcs: ["test.c"],
  214. afdo: true,
  215. compile_multilib: "both",
  216. }
  217. `
  218. result := android.GroupFixturePreparers(
  219. PrepareForTestWithFdoProfile,
  220. prepareForCcTest,
  221. android.FixtureAddTextFile("afdo_profiles_package/foo_arm.afdo", ""),
  222. android.FixtureAddTextFile("afdo_profiles_package/foo_arm64.afdo", ""),
  223. android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
  224. variables.AfdoProfiles = []string{
  225. "foo://afdo_profiles_package:foo_afdo",
  226. }
  227. }),
  228. android.MockFS{
  229. "afdo_profiles_package/Android.bp": []byte(`
  230. soong_namespace {
  231. }
  232. fdo_profile {
  233. name: "foo_afdo",
  234. arch: {
  235. arm: {
  236. profile: "foo_arm.afdo",
  237. },
  238. arm64: {
  239. profile: "foo_arm64.afdo",
  240. }
  241. }
  242. }
  243. `),
  244. }.AddToFixture(),
  245. ).RunTestWithBp(t, bp)
  246. fooArm := result.ModuleForTests("foo", "android_arm_armv7-a-neon_shared")
  247. fooArmCFlags := fooArm.Rule("cc").Args["cFlags"]
  248. if w := "-fprofile-sample-use=afdo_profiles_package/foo_arm.afdo"; !strings.Contains(fooArmCFlags, w) {
  249. t.Errorf("Expected 'foo' to enable afdo, but did not find %q in cflags %q", w, fooArmCFlags)
  250. }
  251. fooArm64 := result.ModuleForTests("foo", "android_arm64_armv8-a_shared")
  252. fooArm64CFlags := fooArm64.Rule("cc").Args["cFlags"]
  253. if w := "-fprofile-sample-use=afdo_profiles_package/foo_arm64.afdo"; !strings.Contains(fooArm64CFlags, w) {
  254. t.Errorf("Expected 'foo' to enable afdo, but did not find %q in cflags %q", w, fooArm64CFlags)
  255. }
  256. }
  257. func TestMultipleAfdoRDeps(t *testing.T) {
  258. t.Parallel()
  259. bp := `
  260. cc_library_shared {
  261. name: "libTest",
  262. srcs: ["test.c"],
  263. static_libs: ["libFoo"],
  264. afdo: true,
  265. }
  266. cc_library_shared {
  267. name: "libBar",
  268. srcs: ["bar.c"],
  269. static_libs: ["libFoo"],
  270. afdo: true,
  271. }
  272. cc_library_static {
  273. name: "libFoo",
  274. srcs: ["foo.c"],
  275. }
  276. `
  277. result := android.GroupFixturePreparers(
  278. PrepareForTestWithFdoProfile,
  279. prepareForCcTest,
  280. android.FixtureAddTextFile("afdo_profiles_package/libTest.afdo", ""),
  281. android.FixtureAddTextFile("afdo_profiles_package/libBar.afdo", ""),
  282. android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
  283. variables.AfdoProfiles = []string{
  284. "libTest://afdo_profiles_package:libTest_afdo",
  285. "libBar://afdo_profiles_package:libBar_afdo",
  286. }
  287. }),
  288. android.MockFS{
  289. "afdo_profiles_package/Android.bp": []byte(`
  290. fdo_profile {
  291. name: "libTest_afdo",
  292. profile: "libTest.afdo",
  293. }
  294. fdo_profile {
  295. name: "libBar_afdo",
  296. profile: "libBar.afdo",
  297. }
  298. `),
  299. }.AddToFixture(),
  300. ).RunTestWithBp(t, bp)
  301. expectedCFlagLibTest := "-fprofile-sample-use=afdo_profiles_package/libTest.afdo"
  302. expectedCFlagLibBar := "-fprofile-sample-use=afdo_profiles_package/libBar.afdo"
  303. libTest := result.ModuleForTests("libTest", "android_arm64_armv8-a_shared")
  304. libFooAfdoVariantWithLibTest := result.ModuleForTests("libFoo", "android_arm64_armv8-a_static_afdo-libTest")
  305. libBar := result.ModuleForTests("libBar", "android_arm64_armv8-a_shared")
  306. libFooAfdoVariantWithLibBar := result.ModuleForTests("libFoo", "android_arm64_armv8-a_static_afdo-libBar")
  307. // Check cFlags of afdo-enabled module and the afdo-variant of its static deps
  308. cFlags := libTest.Rule("cc").Args["cFlags"]
  309. if !strings.Contains(cFlags, expectedCFlagLibTest) {
  310. t.Errorf("Expected 'libTest' to enable afdo, but did not find %q in cflags %q", expectedCFlagLibTest, cFlags)
  311. }
  312. cFlags = libBar.Rule("cc").Args["cFlags"]
  313. if !strings.Contains(cFlags, expectedCFlagLibBar) {
  314. t.Errorf("Expected 'libTest' to enable afdo, but did not find %q in cflags %q", expectedCFlagLibBar, cFlags)
  315. }
  316. cFlags = libFooAfdoVariantWithLibTest.Rule("cc").Args["cFlags"]
  317. if !strings.Contains(cFlags, expectedCFlagLibTest) {
  318. t.Errorf("Expected 'libFooAfdoVariantWithLibTest' to enable afdo, but did not find %q in cflags %q", expectedCFlagLibTest, cFlags)
  319. }
  320. cFlags = libFooAfdoVariantWithLibBar.Rule("cc").Args["cFlags"]
  321. if !strings.Contains(cFlags, expectedCFlagLibBar) {
  322. t.Errorf("Expected 'libBarAfdoVariant' to enable afdo, but did not find %q in cflags %q", expectedCFlagLibBar, cFlags)
  323. }
  324. // Check dependency edges of static deps
  325. if !hasDirectDep(result, libTest.Module(), libFooAfdoVariantWithLibTest.Module()) {
  326. t.Errorf("libTest missing dependency on afdo variant of libFoo")
  327. }
  328. if !hasDirectDep(result, libBar.Module(), libFooAfdoVariantWithLibBar.Module()) {
  329. t.Errorf("libFoo missing dependency on non-afdo variant of libBar")
  330. }
  331. }
  332. func TestAfdoDepsWithoutProfile(t *testing.T) {
  333. t.Parallel()
  334. bp := `
  335. cc_library_shared {
  336. name: "libTest",
  337. srcs: ["test.c"],
  338. static_libs: ["libFoo"],
  339. afdo: true,
  340. }
  341. cc_library_static {
  342. name: "libFoo",
  343. srcs: ["foo.c"],
  344. static_libs: ["libBar"],
  345. }
  346. cc_library_static {
  347. name: "libBar",
  348. srcs: ["bar.c"],
  349. }
  350. `
  351. result := android.GroupFixturePreparers(
  352. PrepareForTestWithFdoProfile,
  353. prepareForCcTest,
  354. ).RunTestWithBp(t, bp)
  355. // Even without a profile path, the afdo enabled libraries should be built with
  356. // -funique-internal-linkage-names.
  357. expectedCFlag := "-funique-internal-linkage-names"
  358. libTest := result.ModuleForTests("libTest", "android_arm64_armv8-a_shared")
  359. libFooAfdoVariant := result.ModuleForTests("libFoo", "android_arm64_armv8-a_static_afdo-libTest")
  360. libBarAfdoVariant := result.ModuleForTests("libBar", "android_arm64_armv8-a_static_afdo-libTest")
  361. // Check cFlags of afdo-enabled module and the afdo-variant of its static deps
  362. cFlags := libTest.Rule("cc").Args["cFlags"]
  363. if !strings.Contains(cFlags, expectedCFlag) {
  364. t.Errorf("Expected 'libTest' to enable afdo, but did not find %q in cflags %q", expectedCFlag, cFlags)
  365. }
  366. cFlags = libFooAfdoVariant.Rule("cc").Args["cFlags"]
  367. if !strings.Contains(cFlags, expectedCFlag) {
  368. t.Errorf("Expected 'libFooAfdoVariant' to enable afdo, but did not find %q in cflags %q", expectedCFlag, cFlags)
  369. }
  370. cFlags = libBarAfdoVariant.Rule("cc").Args["cFlags"]
  371. if !strings.Contains(cFlags, expectedCFlag) {
  372. t.Errorf("Expected 'libBarAfdoVariant' to enable afdo, but did not find %q in cflags %q", expectedCFlag, cFlags)
  373. }
  374. // Check dependency edge from afdo-enabled module to static deps
  375. if !hasDirectDep(result, libTest.Module(), libFooAfdoVariant.Module()) {
  376. t.Errorf("libTest missing dependency on afdo variant of libFoo")
  377. }
  378. if !hasDirectDep(result, libFooAfdoVariant.Module(), libBarAfdoVariant.Module()) {
  379. t.Errorf("libTest missing dependency on afdo variant of libBar")
  380. }
  381. // Verify non-afdo variant exists and doesn't contain afdo
  382. libFoo := result.ModuleForTests("libFoo", "android_arm64_armv8-a_static")
  383. libBar := result.ModuleForTests("libBar", "android_arm64_armv8-a_static")
  384. cFlags = libFoo.Rule("cc").Args["cFlags"]
  385. if strings.Contains(cFlags, expectedCFlag) {
  386. t.Errorf("Expected 'libFoo' to not enable afdo, but found %q in cflags %q", expectedCFlag, cFlags)
  387. }
  388. cFlags = libBar.Rule("cc").Args["cFlags"]
  389. if strings.Contains(cFlags, expectedCFlag) {
  390. t.Errorf("Expected 'libBar' to not enable afdo, but found %q in cflags %q", expectedCFlag, cFlags)
  391. }
  392. // Check dependency edges of static deps
  393. if hasDirectDep(result, libTest.Module(), libFoo.Module()) {
  394. t.Errorf("libTest should not depend on non-afdo variant of libFoo")
  395. }
  396. if !hasDirectDep(result, libFoo.Module(), libBar.Module()) {
  397. t.Errorf("libFoo missing dependency on non-afdo variant of libBar")
  398. }
  399. }