First innings centurion Dimuth Karunaratne then made a fluent 60 as the hosts ended day two on 111 for four, leading by 272 runs at the Galle International Stadium.
Angelo Mathews, on 14, and Roshen Silva, on 10, were batting at close of play after left-arm spinner Keshav Maharaj claimed three wickets for South Africa.
But it was the Sri Lankan bowlers who starred on a dramatic day that witnessed South Africa slip to 51-6 before being bowled out for 126 in the second session of play.
The dismal effort set a new low for South Africa in Sri Lanka, worse than their 169 in Colombo in 2006.
Perera returned impressive figures of 4-46 with his off-spin, while paceman and stand-in skipper Suranga Lakmal took three wickets.
Veteran spinner Rangana Herath started Sri Lanka’s dominance by sending back nightwatchman Maharaj early, and Perera soon took crucial wickets including the dangerous Hashim Amla for 15.
Skipper Faf du Plessis made a gritty 49 and his 64-run seventh-wicket partnership with Vernon Philander, who made 18, was the best that South Africa could muster in their 54.3 overs.
Herath grabbed two wickets while left-arm wrist spinner Lakshan Sandakan claimed one — the three spinners sharing seven wickets in total.
Lakmal did not bowl at all until the 37th over of the innings, but was effective after lunch on day two, rattling the off-stump of du Plessis with a delivery that jagged in sharply.
Lakmal then quickly got rid of the number nine and 10 batsmen to end the innings with figures of 3-21 from only 4.3 overs.
Having established a lead of 161, Sri Lanka quickly set about extending it when they began their second innings, with the openers putting on a 51-run partnership.
Karunaratne became only the second Sri Lanka batsman to score a hundred and a fifty in the same Test against South Africa, but was caught at slip off the bowling of Kagiso Rabada late in the day. (AFP)