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

Side by Side Diff: components/metrics/call_stack_profile_metrics_provider_unittest.cc

Issue 2444143002: Add process lifetime annotations to stack samples. (Closed)
Patch Set: addressed review comments by wittman Created 4 years, 1 month 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 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 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 "components/metrics/call_stack_profile_metrics_provider.h" 5 #include "components/metrics/call_stack_profile_metrics_provider.h"
6 6
7 #include <stddef.h> 7 #include <stddef.h>
8 #include <stdint.h> 8 #include <stdint.h>
9 9
10 #include "base/macros.h" 10 #include "base/macros.h"
(...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after
184 std::vector<Profile> profiles; 184 std::vector<Profile> profiles;
185 for (size_t i = 0; i < arraysize(profile_sample_frames); ++i) { 185 for (size_t i = 0; i < arraysize(profile_sample_frames); ++i) {
186 Profile profile; 186 Profile profile;
187 profile.modules.insert( 187 profile.modules.insert(
188 profile.modules.end(), &profile_modules[i][0], 188 profile.modules.end(), &profile_modules[i][0],
189 &profile_modules[i][0] + arraysize(profile_modules[i])); 189 &profile_modules[i][0] + arraysize(profile_modules[i]));
190 190
191 for (size_t j = 0; j < arraysize(profile_sample_frames[i]); ++j) { 191 for (size_t j = 0; j < arraysize(profile_sample_frames[i]); ++j) {
192 profile.samples.push_back(Sample()); 192 profile.samples.push_back(Sample());
193 Sample& sample = profile.samples.back(); 193 Sample& sample = profile.samples.back();
194 sample.insert(sample.end(), &profile_sample_frames[i][j][0], 194 sample.frames.insert(sample.frames.end(), &profile_sample_frames[i][j][0],
195 &profile_sample_frames[i][j][0] + 195 &profile_sample_frames[i][j][0] +
196 arraysize(profile_sample_frames[i][j])); 196 arraysize(profile_sample_frames[i][j]));
197 } 197 }
198 198
199 profile.profile_duration = profile_durations[i]; 199 profile.profile_duration = profile_durations[i];
200 profile.sampling_period = profile_sampling_periods[i]; 200 profile.sampling_period = profile_sampling_periods[i];
201 201
202 profiles.push_back(profile); 202 profiles.push_back(profile);
203 } 203 }
204 204
205 CallStackProfileMetricsProvider provider; 205 CallStackProfileMetricsProvider provider;
206 provider.OnRecordingEnabled(); 206 provider.OnRecordingEnabled();
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after
303 { Frame(module_base_address + 0x10, 0) } 303 { Frame(module_base_address + 0x10, 0) }
304 }; 304 };
305 305
306 Profile profile; 306 Profile profile;
307 profile.modules.insert(profile.modules.end(), &modules[0], 307 profile.modules.insert(profile.modules.end(), &modules[0],
308 &modules[0] + arraysize(modules)); 308 &modules[0] + arraysize(modules));
309 309
310 for (size_t i = 0; i < arraysize(sample_frames); ++i) { 310 for (size_t i = 0; i < arraysize(sample_frames); ++i) {
311 profile.samples.push_back(Sample()); 311 profile.samples.push_back(Sample());
312 Sample& sample = profile.samples.back(); 312 Sample& sample = profile.samples.back();
313 sample.insert(sample.end(), &sample_frames[i][0], 313 sample.frames.insert(sample.frames.end(), &sample_frames[i][0],
314 &sample_frames[i][0] + arraysize(sample_frames[i])); 314 &sample_frames[i][0] + arraysize(sample_frames[i]));
315 } 315 }
316 316
317 profile.profile_duration = base::TimeDelta::FromMilliseconds(100); 317 profile.profile_duration = base::TimeDelta::FromMilliseconds(100);
318 profile.sampling_period = base::TimeDelta::FromMilliseconds(10); 318 profile.sampling_period = base::TimeDelta::FromMilliseconds(10);
319 319
320 CallStackProfileMetricsProvider provider; 320 CallStackProfileMetricsProvider provider;
321 provider.OnRecordingEnabled(); 321 provider.OnRecordingEnabled();
322 AppendProfiles( 322 AppendProfiles(
323 CallStackProfileParams(CallStackProfileParams::BROWSER_PROCESS, 323 CallStackProfileParams(CallStackProfileParams::BROWSER_PROCESS,
324 CallStackProfileParams::UI_THREAD, 324 CallStackProfileParams::UI_THREAD,
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
386 { Frame(module_base_address + 0x10, 0) } 386 { Frame(module_base_address + 0x10, 0) }
387 }; 387 };
388 388
389 Profile profile; 389 Profile profile;
390 profile.modules.insert(profile.modules.end(), &modules[0], 390 profile.modules.insert(profile.modules.end(), &modules[0],
391 &modules[0] + arraysize(modules)); 391 &modules[0] + arraysize(modules));
392 392
393 for (size_t i = 0; i < arraysize(sample_frames); ++i) { 393 for (size_t i = 0; i < arraysize(sample_frames); ++i) {
394 profile.samples.push_back(Sample()); 394 profile.samples.push_back(Sample());
395 Sample& sample = profile.samples.back(); 395 Sample& sample = profile.samples.back();
396 sample.insert(sample.end(), &sample_frames[i][0], 396 sample.frames.insert(sample.frames.end(), &sample_frames[i][0],
397 &sample_frames[i][0] + arraysize(sample_frames[i])); 397 &sample_frames[i][0] + arraysize(sample_frames[i]));
398 } 398 }
399 399
400 profile.profile_duration = base::TimeDelta::FromMilliseconds(100); 400 profile.profile_duration = base::TimeDelta::FromMilliseconds(100);
401 profile.sampling_period = base::TimeDelta::FromMilliseconds(10); 401 profile.sampling_period = base::TimeDelta::FromMilliseconds(10);
402 402
403 CallStackProfileMetricsProvider provider; 403 CallStackProfileMetricsProvider provider;
404 provider.OnRecordingEnabled(); 404 provider.OnRecordingEnabled();
405 AppendProfiles(CallStackProfileParams(CallStackProfileParams::BROWSER_PROCESS, 405 AppendProfiles(CallStackProfileParams(CallStackProfileParams::BROWSER_PROCESS,
406 CallStackProfileParams::UI_THREAD, 406 CallStackProfileParams::UI_THREAD,
407 CallStackProfileParams::PROCESS_STARTUP, 407 CallStackProfileParams::PROCESS_STARTUP,
(...skipping 30 matching lines...) Expand all
438 entry.address()); 438 entry.address());
439 ASSERT_TRUE(entry.has_module_id_index()); 439 ASSERT_TRUE(entry.has_module_id_index());
440 EXPECT_EQ(sample_frames[i][j].module_index, 440 EXPECT_EQ(sample_frames[i][j].module_index,
441 static_cast<size_t>(entry.module_id_index())); 441 static_cast<size_t>(entry.module_id_index()));
442 } 442 }
443 } 443 }
444 } 444 }
445 445
446 // Checks that unknown modules produce an empty Entry. 446 // Checks that unknown modules produce an empty Entry.
447 TEST_F(CallStackProfileMetricsProviderTest, UnknownModule) { 447 TEST_F(CallStackProfileMetricsProviderTest, UnknownModule) {
448 const Frame frame(0x1000, Frame::kUnknownModuleIndex);
449
450 Profile profile; 448 Profile profile;
451 449 profile.samples.push_back(Sample(Frame(0x1000, Frame::kUnknownModuleIndex)));
452 profile.samples.push_back(Sample(1, frame));
453
454 profile.profile_duration = base::TimeDelta::FromMilliseconds(100); 450 profile.profile_duration = base::TimeDelta::FromMilliseconds(100);
455 profile.sampling_period = base::TimeDelta::FromMilliseconds(10); 451 profile.sampling_period = base::TimeDelta::FromMilliseconds(10);
456 452
457 CallStackProfileMetricsProvider provider; 453 CallStackProfileMetricsProvider provider;
458 provider.OnRecordingEnabled(); 454 provider.OnRecordingEnabled();
459 AppendProfiles( 455 AppendProfiles(
460 CallStackProfileParams(CallStackProfileParams::BROWSER_PROCESS, 456 CallStackProfileParams(CallStackProfileParams::BROWSER_PROCESS,
461 CallStackProfileParams::UI_THREAD, 457 CallStackProfileParams::UI_THREAD,
462 CallStackProfileParams::PROCESS_STARTUP, 458 CallStackProfileParams::PROCESS_STARTUP,
463 CallStackProfileParams::MAY_SHUFFLE), 459 CallStackProfileParams::MAY_SHUFFLE),
(...skipping 18 matching lines...) Expand all
482 EXPECT_FALSE(entry.has_module_id_index()); 478 EXPECT_FALSE(entry.has_module_id_index());
483 } 479 }
484 480
485 // Checks that pending profiles are only passed back to ProvideGeneralMetrics 481 // Checks that pending profiles are only passed back to ProvideGeneralMetrics
486 // once. 482 // once.
487 TEST_F(CallStackProfileMetricsProviderTest, ProfilesProvidedOnlyOnce) { 483 TEST_F(CallStackProfileMetricsProviderTest, ProfilesProvidedOnlyOnce) {
488 CallStackProfileMetricsProvider provider; 484 CallStackProfileMetricsProvider provider;
489 for (int i = 0; i < 2; ++i) { 485 for (int i = 0; i < 2; ++i) {
490 Profile profile; 486 Profile profile;
491 profile.samples.push_back( 487 profile.samples.push_back(
492 Sample(1, Frame(0x1000, Frame::kUnknownModuleIndex))); 488 Sample((Frame(0x1000, Frame::kUnknownModuleIndex))));
493 489
494 profile.profile_duration = base::TimeDelta::FromMilliseconds(100); 490 profile.profile_duration = base::TimeDelta::FromMilliseconds(100);
495 // Use the sampling period to distinguish the two profiles. 491 // Use the sampling period to distinguish the two profiles.
496 profile.sampling_period = base::TimeDelta::FromMilliseconds(i); 492 profile.sampling_period = base::TimeDelta::FromMilliseconds(i);
497 493
498 provider.OnRecordingEnabled(); 494 provider.OnRecordingEnabled();
499 AppendProfiles( 495 AppendProfiles(
500 CallStackProfileParams(CallStackProfileParams::BROWSER_PROCESS, 496 CallStackProfileParams(CallStackProfileParams::BROWSER_PROCESS,
501 CallStackProfileParams::UI_THREAD, 497 CallStackProfileParams::UI_THREAD,
502 CallStackProfileParams::PROCESS_STARTUP, 498 CallStackProfileParams::PROCESS_STARTUP,
(...skipping 10 matching lines...) Expand all
513 ASSERT_TRUE(call_stack_profile.has_sampling_period_ms()); 509 ASSERT_TRUE(call_stack_profile.has_sampling_period_ms());
514 EXPECT_EQ(i, call_stack_profile.sampling_period_ms()); 510 EXPECT_EQ(i, call_stack_profile.sampling_period_ms());
515 } 511 }
516 } 512 }
517 513
518 // Checks that pending profiles are provided to ProvideGeneralMetrics 514 // Checks that pending profiles are provided to ProvideGeneralMetrics
519 // when collected before CallStackProfileMetricsProvider is instantiated. 515 // when collected before CallStackProfileMetricsProvider is instantiated.
520 TEST_F(CallStackProfileMetricsProviderTest, 516 TEST_F(CallStackProfileMetricsProviderTest,
521 ProfilesProvidedWhenCollectedBeforeInstantiation) { 517 ProfilesProvidedWhenCollectedBeforeInstantiation) {
522 Profile profile; 518 Profile profile;
523 profile.samples.push_back( 519 profile.samples.push_back(Sample(Frame(0x1000, Frame::kUnknownModuleIndex)));
524 Sample(1, Frame(0x1000, Frame::kUnknownModuleIndex)));
525
526 profile.profile_duration = base::TimeDelta::FromMilliseconds(100); 520 profile.profile_duration = base::TimeDelta::FromMilliseconds(100);
527 profile.sampling_period = base::TimeDelta::FromMilliseconds(10); 521 profile.sampling_period = base::TimeDelta::FromMilliseconds(10);
528 522
529 AppendProfiles( 523 AppendProfiles(
530 CallStackProfileParams(CallStackProfileParams::BROWSER_PROCESS, 524 CallStackProfileParams(CallStackProfileParams::BROWSER_PROCESS,
531 CallStackProfileParams::UI_THREAD, 525 CallStackProfileParams::UI_THREAD,
532 CallStackProfileParams::PROCESS_STARTUP, 526 CallStackProfileParams::PROCESS_STARTUP,
533 CallStackProfileParams::MAY_SHUFFLE), 527 CallStackProfileParams::MAY_SHUFFLE),
534 std::vector<Profile>(1, profile)); 528 std::vector<Profile>(1, profile));
535 529
536 CallStackProfileMetricsProvider provider; 530 CallStackProfileMetricsProvider provider;
537 provider.OnRecordingEnabled(); 531 provider.OnRecordingEnabled();
538 ChromeUserMetricsExtension uma_proto; 532 ChromeUserMetricsExtension uma_proto;
539 provider.ProvideGeneralMetrics(&uma_proto); 533 provider.ProvideGeneralMetrics(&uma_proto);
540 534
541 EXPECT_EQ(1, uma_proto.sampled_profile_size()); 535 EXPECT_EQ(1, uma_proto.sampled_profile_size());
542 } 536 }
543 537
544 // Checks that pending profiles are not provided to ProvideGeneralMetrics 538 // Checks that pending profiles are not provided to ProvideGeneralMetrics
545 // while recording is disabled. 539 // while recording is disabled.
546 TEST_F(CallStackProfileMetricsProviderTest, ProfilesNotProvidedWhileDisabled) { 540 TEST_F(CallStackProfileMetricsProviderTest, ProfilesNotProvidedWhileDisabled) {
547 Profile profile; 541 Profile profile;
548 profile.samples.push_back( 542 profile.samples.push_back(Sample(Frame(0x1000, Frame::kUnknownModuleIndex)));
549 Sample(1, Frame(0x1000, Frame::kUnknownModuleIndex)));
550
551 profile.profile_duration = base::TimeDelta::FromMilliseconds(100); 543 profile.profile_duration = base::TimeDelta::FromMilliseconds(100);
552 profile.sampling_period = base::TimeDelta::FromMilliseconds(10); 544 profile.sampling_period = base::TimeDelta::FromMilliseconds(10);
553 545
554 CallStackProfileMetricsProvider provider; 546 CallStackProfileMetricsProvider provider;
555 provider.OnRecordingDisabled(); 547 provider.OnRecordingDisabled();
556 AppendProfiles( 548 AppendProfiles(
557 CallStackProfileParams(CallStackProfileParams::BROWSER_PROCESS, 549 CallStackProfileParams(CallStackProfileParams::BROWSER_PROCESS,
558 CallStackProfileParams::UI_THREAD, 550 CallStackProfileParams::UI_THREAD,
559 CallStackProfileParams::PROCESS_STARTUP, 551 CallStackProfileParams::PROCESS_STARTUP,
560 CallStackProfileParams::MAY_SHUFFLE), 552 CallStackProfileParams::MAY_SHUFFLE),
561 std::vector<Profile>(1, profile)); 553 std::vector<Profile>(1, profile));
562 ChromeUserMetricsExtension uma_proto; 554 ChromeUserMetricsExtension uma_proto;
563 provider.ProvideGeneralMetrics(&uma_proto); 555 provider.ProvideGeneralMetrics(&uma_proto);
564 556
565 EXPECT_EQ(0, uma_proto.sampled_profile_size()); 557 EXPECT_EQ(0, uma_proto.sampled_profile_size());
566 } 558 }
567 559
568 // Checks that pending profiles are not provided to ProvideGeneralMetrics 560 // Checks that pending profiles are not provided to ProvideGeneralMetrics
569 // if recording is disabled while profiling. 561 // if recording is disabled while profiling.
570 TEST_F(CallStackProfileMetricsProviderTest, 562 TEST_F(CallStackProfileMetricsProviderTest,
571 ProfilesNotProvidedAfterChangeToDisabled) { 563 ProfilesNotProvidedAfterChangeToDisabled) {
572 Profile profile; 564 Profile profile;
573 profile.samples.push_back( 565 profile.samples.push_back(Sample(Frame(0x1000, Frame::kUnknownModuleIndex)));
574 Sample(1, Frame(0x1000, Frame::kUnknownModuleIndex)));
575
576 profile.profile_duration = base::TimeDelta::FromMilliseconds(100); 566 profile.profile_duration = base::TimeDelta::FromMilliseconds(100);
577 profile.sampling_period = base::TimeDelta::FromMilliseconds(10); 567 profile.sampling_period = base::TimeDelta::FromMilliseconds(10);
578 568
579 CallStackProfileMetricsProvider provider; 569 CallStackProfileMetricsProvider provider;
580 provider.OnRecordingEnabled(); 570 provider.OnRecordingEnabled();
581 base::StackSamplingProfiler::CompletedCallback callback = 571 base::StackSamplingProfiler::CompletedCallback callback =
582 CallStackProfileMetricsProvider::GetProfilerCallback( 572 CallStackProfileMetricsProvider::GetProfilerCallback(
583 CallStackProfileParams(CallStackProfileParams::BROWSER_PROCESS, 573 CallStackProfileParams(CallStackProfileParams::BROWSER_PROCESS,
584 CallStackProfileParams::UI_THREAD, 574 CallStackProfileParams::UI_THREAD,
585 CallStackProfileParams::PROCESS_STARTUP, 575 CallStackProfileParams::PROCESS_STARTUP,
586 CallStackProfileParams::MAY_SHUFFLE)); 576 CallStackProfileParams::MAY_SHUFFLE));
587 577
588 provider.OnRecordingDisabled(); 578 provider.OnRecordingDisabled();
589 callback.Run(std::vector<Profile>(1, profile)); 579 callback.Run(std::vector<Profile>(1, profile));
590 ChromeUserMetricsExtension uma_proto; 580 ChromeUserMetricsExtension uma_proto;
591 provider.ProvideGeneralMetrics(&uma_proto); 581 provider.ProvideGeneralMetrics(&uma_proto);
592 582
593 EXPECT_EQ(0, uma_proto.sampled_profile_size()); 583 EXPECT_EQ(0, uma_proto.sampled_profile_size());
594 } 584 }
595 585
596 // Checks that pending profiles are not provided to ProvideGeneralMetrics if 586 // Checks that pending profiles are not provided to ProvideGeneralMetrics if
597 // recording is enabled, but then disabled and reenabled while profiling. 587 // recording is enabled, but then disabled and reenabled while profiling.
598 TEST_F(CallStackProfileMetricsProviderTest, 588 TEST_F(CallStackProfileMetricsProviderTest,
599 ProfilesNotProvidedAfterChangeToDisabledThenEnabled) { 589 ProfilesNotProvidedAfterChangeToDisabledThenEnabled) {
600 Profile profile; 590 Profile profile;
601 profile.samples.push_back( 591 profile.samples.push_back(Sample(Frame(0x1000, Frame::kUnknownModuleIndex)));
602 Sample(1, Frame(0x1000, Frame::kUnknownModuleIndex)));
603
604 profile.profile_duration = base::TimeDelta::FromMilliseconds(100); 592 profile.profile_duration = base::TimeDelta::FromMilliseconds(100);
605 profile.sampling_period = base::TimeDelta::FromMilliseconds(10); 593 profile.sampling_period = base::TimeDelta::FromMilliseconds(10);
606 594
607 CallStackProfileMetricsProvider provider; 595 CallStackProfileMetricsProvider provider;
608 provider.OnRecordingEnabled(); 596 provider.OnRecordingEnabled();
609 base::StackSamplingProfiler::CompletedCallback callback = 597 base::StackSamplingProfiler::CompletedCallback callback =
610 CallStackProfileMetricsProvider::GetProfilerCallback( 598 CallStackProfileMetricsProvider::GetProfilerCallback(
611 CallStackProfileParams(CallStackProfileParams::BROWSER_PROCESS, 599 CallStackProfileParams(CallStackProfileParams::BROWSER_PROCESS,
612 CallStackProfileParams::UI_THREAD, 600 CallStackProfileParams::UI_THREAD,
613 CallStackProfileParams::PROCESS_STARTUP, 601 CallStackProfileParams::PROCESS_STARTUP,
614 CallStackProfileParams::MAY_SHUFFLE)); 602 CallStackProfileParams::MAY_SHUFFLE));
615 603
616 provider.OnRecordingDisabled(); 604 provider.OnRecordingDisabled();
617 provider.OnRecordingEnabled(); 605 provider.OnRecordingEnabled();
618 callback.Run(std::vector<Profile>(1, profile)); 606 callback.Run(std::vector<Profile>(1, profile));
619 ChromeUserMetricsExtension uma_proto; 607 ChromeUserMetricsExtension uma_proto;
620 provider.ProvideGeneralMetrics(&uma_proto); 608 provider.ProvideGeneralMetrics(&uma_proto);
621 609
622 EXPECT_EQ(0, uma_proto.sampled_profile_size()); 610 EXPECT_EQ(0, uma_proto.sampled_profile_size());
623 } 611 }
624 612
625 // Checks that pending profiles are not provided to ProvideGeneralMetrics 613 // Checks that pending profiles are not provided to ProvideGeneralMetrics
626 // if recording is disabled, but then enabled while profiling. 614 // if recording is disabled, but then enabled while profiling.
627 TEST_F(CallStackProfileMetricsProviderTest, 615 TEST_F(CallStackProfileMetricsProviderTest,
628 ProfilesNotProvidedAfterChangeFromDisabled) { 616 ProfilesNotProvidedAfterChangeFromDisabled) {
629 Profile profile; 617 Profile profile;
630 profile.samples.push_back( 618 profile.samples.push_back(Sample(Frame(0x1000, Frame::kUnknownModuleIndex)));
631 Sample(1, Frame(0x1000, Frame::kUnknownModuleIndex)));
632
633 profile.profile_duration = base::TimeDelta::FromMilliseconds(100); 619 profile.profile_duration = base::TimeDelta::FromMilliseconds(100);
634 profile.sampling_period = base::TimeDelta::FromMilliseconds(10); 620 profile.sampling_period = base::TimeDelta::FromMilliseconds(10);
635 621
636 CallStackProfileMetricsProvider provider; 622 CallStackProfileMetricsProvider provider;
637 provider.OnRecordingDisabled(); 623 provider.OnRecordingDisabled();
638 base::StackSamplingProfiler::CompletedCallback callback = 624 base::StackSamplingProfiler::CompletedCallback callback =
639 CallStackProfileMetricsProvider::GetProfilerCallback( 625 CallStackProfileMetricsProvider::GetProfilerCallback(
640 CallStackProfileParams(CallStackProfileParams::BROWSER_PROCESS, 626 CallStackProfileParams(CallStackProfileParams::BROWSER_PROCESS,
641 CallStackProfileParams::UI_THREAD, 627 CallStackProfileParams::UI_THREAD,
642 CallStackProfileParams::PROCESS_STARTUP, 628 CallStackProfileParams::PROCESS_STARTUP,
643 CallStackProfileParams::MAY_SHUFFLE)); 629 CallStackProfileParams::MAY_SHUFFLE));
644 630
645 provider.OnRecordingEnabled(); 631 provider.OnRecordingEnabled();
646 callback.Run(std::vector<Profile>(1, profile)); 632 callback.Run(std::vector<Profile>(1, profile));
647 ChromeUserMetricsExtension uma_proto; 633 ChromeUserMetricsExtension uma_proto;
648 provider.ProvideGeneralMetrics(&uma_proto); 634 provider.ProvideGeneralMetrics(&uma_proto);
649 635
650 EXPECT_EQ(0, uma_proto.sampled_profile_size()); 636 EXPECT_EQ(0, uma_proto.sampled_profile_size());
651 } 637 }
652 638
653 } // namespace metrics 639 } // namespace metrics
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698